Compare commits

...
515 Commits
Author SHA1 Message Date
Andre601 0c36667116 Version 5.6.0 2025-06-25 20:44:01 +02:00
Andre601 3417d7c0be Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.2' (#456) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/456
2025-06-25 14:05:24 +02:00
Andre601's Bot 96fa871204 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.2 2025-06-25 12:02:49 +00:00
Andre601 aaacd9944f Merge pull request 'Update maven Docker tag to v3.9.10' (#455) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/455
2025-06-24 14:35:21 +02:00
Andre601's Bot af44324cf1 Update maven Docker tag to v3.9.10 2025-06-24 12:02:49 +00:00
Andre601 77b6897bd4 Add note about favicon resizing 2025-06-23 23:21:02 +02:00
Andre601 9d963199ae Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.4.0' (#454) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/454
2025-06-21 14:03:06 +02:00
Andre601's Bot 580b87ebb5 Update dependency com.viaversion:viaversion-api to v5.4.0 2025-06-21 12:02:16 +00:00
Andre601 efd5762162 Update README 2025-06-19 23:55:08 +02:00
Andre601 62261ae6ed Update config.yml example in getting-started 2025-06-19 21:29:06 +02:00
Andre601 e52bfdf60b Add faviconStrategy config option 2025-06-19 21:18:41 +02:00
Andre601 0152ba3e1a Update default.yml in getting-started.md 2025-06-19 17:04:55 +02:00
Andre601 090787e292 Add german tutorial 2025-06-19 16:40:55 +02:00
Andre601 25d14eeaae Add indonesian tutorial 2025-06-19 16:32:57 +02:00
Andre601 386d490596 Merge pull request 'Update all non-major dependencies to v4.23.0' (#453) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/453
2025-06-18 20:56:11 +02:00
Andre601's Bot 207ce12452 Update all non-major dependencies to v4.23.0 2025-06-18 18:48:21 +00:00
Andre601 b87703c36c Merge pull request 'Update dependency net.md-5:bungeecord-api to v1.21-R0.3' (#452) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/452
2025-06-16 14:05:20 +02:00
Andre601's Bot 41677d0635 Update dependency net.md-5:bungeecord-api to v1.21-R0.3 2025-06-16 12:02:50 +00:00
Andre601 dfdb2aa767 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.1' (#451) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/451
2025-06-07 14:58:29 +02:00
Andre601's Bot d14c5f80e8 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.1 2025-06-07 12:02:12 +00:00
Andre601 bd9e376d08 Merge pull request 'Implement support for merging images' (#450) from feature/favicon-merging into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/450
2025-06-03 14:54:15 +02:00
Andre601 578242078b Move local and random Favicon handling to the start 2025-06-03 14:33:36 +02:00
Andre601 f84842729d Update documentation 2025-06-03 01:04:39 +02:00
Andre601 1daeecbbcf Create proper Favicon merging system 2025-06-03 00:56:37 +02:00
Andre601 5dcab6c37c Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.0' (#449) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/449
2025-05-30 14:02:34 +02:00
Andre601's Bot a146a10d53 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.0 2025-05-30 12:02:12 +00:00
Andre601 75db0d5e96 Add Favicon Merging 2025-05-28 20:17:40 +02:00
Andre601 644dd401d4 Update profiles option page 2025-05-28 19:58:14 +02:00
Andre601 32d85c6be1 Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.5' (#448) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/448
2025-05-23 14:04:19 +02:00
Andre601's Bot 1b47af6714 Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.5 2025-05-23 12:03:00 +00:00
Andre601 4544696a54 Merge pull request 'Update dependency mkdocs-material to v9.6.14' (#447) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/447
2025-05-14 12:23:10 +00:00
Andre601's Bot a84848daee Update dependency mkdocs-material to v9.6.14 2025-05-14 12:03:01 +00:00
Andre601 3f8dd90e28 Merge pull request 'Update dependency net.kyori:adventure-platform-bungeecord to v4.4.0' (#446) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/446
2025-05-11 15:40:33 +00:00
Andre601's Bot f633741988 Update dependency net.kyori:adventure-platform-bungeecord to v4.4.0 2025-05-11 12:02:21 +00:00
Andre601 7e9ea9f470 Merge pull request 'Update dependency mkdocs-material to v9.6.13' (#445) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/445
2025-05-10 12:14:35 +00:00
Andre601's Bot c2c00dc47f Update dependency mkdocs-material to v9.6.13 2025-05-10 12:02:52 +00:00
Andre601 027503efab Merge pull request 'Update dependency net.william278:papiproxybridge to v1.8.1' (#444) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/444
2025-05-06 12:31:54 +00:00
Andre601's Bot 7dd78cbbfc Update dependency net.william278:papiproxybridge to v1.8.1 2025-05-06 12:03:06 +00:00
Andre601 b27b8e78bd Merge pull request 'Update all non-major dependencies to v4.21.0' (#443) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/443
2025-04-30 12:13:12 +00:00
Andre601's Bot ad5b07feda Update all non-major dependencies to v4.21.0 2025-04-30 12:03:04 +00:00
Andre601 d79784d1c0 Merge pull request 'Update all non-major dependencies to v4.1.1' (#442) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/442
2025-04-29 12:06:11 +00:00
Andre601's Bot ef84e85426 Update all non-major dependencies to v4.1.1 2025-04-29 12:02:50 +00:00
Andre601 35782809ac Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.4' (#441) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/441
2025-04-25 12:08:42 +00:00
Andre601's Bot 3e3c4903e4 Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.4 2025-04-25 12:02:49 +00:00
Andre601 79b45fb29d Merge pull request 'Update dependency com.google.code.gson:gson to v2.13.1' (#440) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/440
2025-04-24 14:20:27 +00:00
Andre601's Bot 46f40294e2 Update dependency com.google.code.gson:gson to v2.13.1 2025-04-24 14:08:23 +00:00
Andre601 ca5ab5d221 Merge pull request 'Update dependency mkdocs-material to v9.6.12' (#439) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/439
2025-04-17 12:04:54 +00:00
Andre601's Bot b2e5d7ae28 Update dependency mkdocs-material to v9.6.12 2025-04-17 12:02:51 +00:00
Andre601 649e9f07ef Merge pull request 'Update all non-major dependencies' (#438) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/438
2025-04-15 12:04:27 +00:00
Andre601's Bot eaa86aa93b Update all non-major dependencies 2025-04-15 12:02:50 +00:00
Andre601 8a90619810 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.3.2' (#437) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/437
2025-04-14 12:38:48 +00:00
Andre601's Bot 351db260ce Update dependency com.viaversion:viaversion-api to v5.3.2 2025-04-14 12:21:57 +00:00
Andre601 bcc9d88e8c Update appearance of playercount options in docs 2025-04-12 23:41:08 +00:00
Andre601 9c849157d3 Merge pull request 'Update all non-major dependencies' (#436) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/436
2025-04-12 12:12:05 +00:00
Andre601's Bot f171c951e7 Update all non-major dependencies 2025-04-12 12:02:23 +00:00
Andre601 cae808e3fc Add example for priority 2025-04-10 22:06:15 +02:00
Andre601 ae8e6304f9 Merge pull request 'Update dependency com.google.guava:guava to v33.4.7-jre' (#435) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/435
2025-04-09 12:26:44 +00:00
Andre601's Bot c975ba79b3 Update dependency com.google.guava:guava to v33.4.7-jre 2025-04-09 12:03:17 +00:00
Andre601 83fb13e1f2 Update wiki links 2025-04-07 23:49:05 +00:00
Andre601 586351e277 Update announcement banner 2025-04-08 01:46:40 +02:00
Andre601 098b6be0f4 Refactor profiles page 2025-04-08 01:40:36 +02:00
Andre601 1c881d2832 Update API Docs 2025-04-07 23:40:42 +02:00
Andre601 e6f3d122c7 Merge pull request 'Migrate renovate config' (#434) from renovate/migrate-config into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/434
2025-04-06 01:54:03 +00:00
Andre601's Bot 759474b344 Migrate config renovate.json 2025-04-06 01:52:21 +00:00
Andre601 6aef4c2de9 Enable config migration 2025-04-06 01:51:29 +00:00
Andre601 64d7c81c58 Merge pull request 'Update all non-major dependencies to v4.20.0' (#433) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/433
2025-04-06 01:30:06 +00:00
Andre601's Bot a070708323 Update all non-major dependencies to v4.20.0 2025-04-06 01:29:09 +00:00
Andre601 e9ba86508c Merge pull request 'Update dependency space.arim.libertybans:bans-api to v1.1.0' (#432) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/432
2025-04-05 12:36:42 +00:00
Andre601's Bot c1e3638534 Update dependency space.arim.libertybans:bans-api to v1.1.0 2025-04-05 12:02:18 +00:00
Andre601 f5260f3be1 Merge pull request 'Update dependency mkdocs-material to v9.6.11' (#431) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/431
2025-04-01 12:04:58 +00:00
Andre601's Bot 51372aa8f4 Update dependency mkdocs-material to v9.6.11 2025-04-01 12:02:14 +00:00
Andre601 025c9f4423 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.3.1' (#430) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/430
2025-03-31 12:25:08 +00:00
Andre601's Bot 99c34dd343 Update dependency com.viaversion:viaversion-api to v5.3.1 2025-03-31 12:02:53 +00:00
Andre601 cd91b799d6 Merge pull request 'Update dependency mkdocs-material to v9.6.10' (#429) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/429
2025-03-30 13:04:23 +00:00
Andre601's Bot 5b7eb014a3 Update dependency mkdocs-material to v9.6.10 2025-03-30 12:03:16 +00:00
Andre601 ad32952b97 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.3.0' (#428) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/428
2025-03-29 12:03:56 +00:00
Andre601's Bot 4a1e552d5d Update dependency com.viaversion:viaversion-api to v5.3.0 2025-03-29 12:02:13 +00:00
Andre601 ea1394dce9 Merge pull request 'Update all non-major dependencies' (#427) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/427
2025-03-28 12:10:16 +00:00
Andre601's Bot 317fa631e9 Update all non-major dependencies 2025-03-28 12:02:24 +00:00
Andre601 5dd26f6ab8 Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.3' (#426) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/426
2025-03-27 12:05:14 +00:00
Andre601's Bot ba82df45ef Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.3 2025-03-27 12:03:35 +00:00
Andre601 d76339188d Merge pull request 'Update all non-major dependencies' (#425) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/425
2025-03-26 12:21:12 +00:00
Andre601's Bot a9fb8f3ed6 Update all non-major dependencies 2025-03-26 12:02:54 +00:00
Andre601 18291a6865 Merge pull request 'Update dependency net.william278:papiproxybridge to v1.8' (#424) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/424
2025-03-23 13:12:05 +00:00
Andre601's Bot 83a1808ebc Update dependency net.william278:papiproxybridge to v1.8 2025-03-23 12:02:03 +00:00
Andre601 197967dea9 Use jspecify for (Non)Null annotations 2025-03-20 13:51:05 +01:00
Andre601 b25b65faba Merge pull request 'Update dependency com.google.guava:guava to v33.4.5-jre' (#423) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/423
2025-03-20 12:27:21 +00:00
Andre601's Bot fafcd3ae18 Update dependency com.google.guava:guava to v33.4.5-jre 2025-03-20 12:21:06 +00:00
Andre601 daae88074f Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.18' (#422) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/422
2025-03-19 12:02:45 +00:00
Andre601's Bot fbe019214d Update dependency ch.qos.logback:logback-classic to v1.5.18 2025-03-19 12:01:59 +00:00
Andre601 3e380342a7 Merge pull request 'Update dependency mkdocs-material to v9.6.9' (#421) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/421
2025-03-17 12:42:58 +00:00
Andre601's Bot fd2dbd2edb Update dependency mkdocs-material to v9.6.9 2025-03-17 12:02:33 +00:00
Andre601 e969208ae9 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.12.1' (#420) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/420
2025-03-16 12:20:14 +00:00
Andre601's Bot 77aa404e06 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.12.1 2025-03-16 12:10:40 +00:00
Andre601 a6c1840858 Merge pull request 'Update dependency mkdocs-material to v9.6.8' (#419) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/419
2025-03-13 12:35:37 +00:00
Andre601's Bot 762bd1d0fd Update dependency mkdocs-material to v9.6.8 2025-03-13 12:02:56 +00:00
Andre601 02ce580433 Merge pull request 'Update dependency com.github.LeonMangler:PremiumVanishAPI to v2.9.18-2' (#418) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/418
2025-03-09 12:19:41 +00:00
Andre601's Bot c7b7feb476 Update dependency com.github.LeonMangler:PremiumVanishAPI to v2.9.18-2 2025-03-09 12:06:02 +00:00
Andre601 0e145def83 Merge pull request 'Update dependency mkdocs-material to v9.6.7' (#417) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/417
2025-03-03 12:14:54 +00:00
Andre601's Bot 03e32feb1d Update dependency mkdocs-material to v9.6.7 2025-03-03 12:04:14 +00:00
Andre601 dbab282901 Merge pull request 'Update dependency mkdocs-material to v9.6.6' (#416) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/416
2025-03-01 12:10:43 +00:00
Andre601's Bot bd6b599267 Update dependency mkdocs-material to v9.6.6 2025-03-01 12:02:02 +00:00
Andre601 1a63430c1e Merge pull request 'Update all non-major dependencies' (#415) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/415
2025-02-26 12:14:58 +00:00
Andre601's Bot 661f9e6ad4 Update all non-major dependencies 2025-02-26 12:03:25 +00:00
Andre601 6bd8d40ff4 Remove temporary SVG Icon 2025-02-24 03:40:32 +01:00
Andre601 16b74433ff Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.12.0' (#414) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/414
2025-02-22 12:17:18 +00:00
Andre601's Bot 1aaafe474f Update dependency org.junit.jupiter:junit-jupiter-engine to v5.12.0 2025-02-22 12:03:51 +00:00
Andre601 26a7697b0f Merge pull request 'Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.0' (#413) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/413
2025-02-21 12:05:52 +00:00
Andre601's Bot ec6b653988 Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.0 2025-02-21 12:04:18 +00:00
Andre601 854eb67c54 Further API Doc updates 2025-02-20 14:56:29 +01:00
Andre601 00511f6e97 Update API doc page 2025-02-20 14:42:00 +01:00
Andre601 16eebb23a5 Update docs 2025-02-20 14:38:04 +01:00
Andre601 faae641c32 Merge pull request 'Update dependency mkdocs-material to v9.6.5' (#412) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/412
2025-02-20 12:57:14 +00:00
Andre601's Bot 4fa542a242 Update dependency mkdocs-material to v9.6.5 2025-02-20 12:02:25 +00:00
Andre601 2dc1f7ccc1 Update icon used for velocity + other stuff 2025-02-19 00:58:20 +01:00
Andre601 dd7b1a7392 Improve Expressions page 2025-02-17 20:21:20 +01:00
Andre601 a90d241cd2 Merge pull request 'Update all non-major dependencies to v4.19.0' (#411) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/411
2025-02-17 12:06:41 +00:00
Andre601's Bot 452ac00ee7 Update all non-major dependencies to v4.19.0 2025-02-17 12:03:06 +00:00
Andre601 f139270f0e Use inlinehilite 2025-02-16 21:50:38 +01:00
Andre601 b212b2af0f Add MiniMessage Pygments lexer to requirements.txt 2025-02-16 21:23:35 +01:00
Andre601 0d506379cf Add MiniMessage Pygment lexer 2025-02-16 21:22:21 +01:00
Andre601 995793e66d Update api-version and add safety-check to PaperCore 2025-02-16 21:20:54 +01:00
Andre601 f9ebc60d64 Add new SayanVanish placeholders 2025-02-13 19:18:39 +00:00
Andre601 1d531a32e3 Merge pull request 'Update all non-major dependencies to v1.6.5' (#410) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/410
2025-02-13 19:10:12 +00:00
Andre601's Bot 36340d9b9d Update all non-major dependencies to v1.6.5 2025-02-13 19:03:39 +00:00
Andre601 d023e22934 Merge pull request 'Update dependency mkdocs-material to v9.6.4' (#409) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/409
2025-02-12 13:52:19 +00:00
Andre601's Bot 260a0b4835 Update dependency mkdocs-material to v9.6.4 2025-02-12 12:02:41 +00:00
Andre601 3f18aaaf5b renovate.json aktualisiert 2025-02-11 19:56:22 +00:00
Andre601 3f0e7897d4 No longer use allorigins.win
Codeberg apparently no longer causes CORS issues for JS fetched requests.
2025-02-10 12:11:23 +00:00
Andre601 4bd35c810b Add subcommand permissions for profiles commands. 2025-02-09 02:58:52 +01:00
Andre601 b081be8f53 Improve Command docs 2025-02-09 02:40:58 +01:00
Andre601 eb474d061b Merge pull request 'Update dependency mkdocs-material to v9.6.3' (#407) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/407
2025-02-07 12:42:35 +00:00
Andre601 edbc893c65 Ignore 2.0.0-SNAPSHOT for cloud 2025-02-07 12:36:37 +00:00
Andre601's Bot d03dce9b29 Update all non-major dependencies 2025-02-07 12:02:26 +00:00
Andre601 de7d011216 Fix cloud-paper not being compiled into project 2025-02-06 13:45:21 +01:00
Andre601 4a2cb2078d Compile the bungee cloud dependency and make enum public. 2025-02-05 21:28:56 +01:00
Andre601 05381bd538 Rename CommandHandler to CommandManagerInterface 2025-02-04 23:17:05 +01:00
Andre601 51e561f2ba Use records instead of classes for Player implementations 2025-02-04 23:11:30 +01:00
Andre601 71a3bddc62 Remove no longer existing overrides and update docs 2025-02-04 22:16:09 +01:00
Andre601 3eeffd5520 Merge pull request 'Use Cloud for Command handling' (#400) from feature/cloud-command-system into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/400
2025-02-04 20:40:40 +00:00
Andre601 3590e4fa12 Merge pull request 'Update dependency mkdocs-material to v9.6.2' (#405) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/405
2025-02-04 12:54:04 +00:00
Andre601's Bot e1e7907d0f Update dependency mkdocs-material to v9.6.2 2025-02-04 12:02:22 +00:00
Andre601 1e8f71092c Update ExpressionParser 2025-02-04 02:33:47 +01:00
Andre601 1c12180fe3 Merge branch 'master' into feature/cloud-command-system 2025-02-03 17:54:42 +01:00
Andre601 7a41e27788 Merge pull request 'Use MkDocs macros plugin for API reference generation' (#398) from feature/docs/better-autogen-apidocs into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/398
2025-02-03 16:48:20 +00:00
Andre601 ddfc8763c4 Bump Sayanvanish to 1.6.4 and add it as addon to wiki 2025-02-03 14:28:38 +01:00
Andre601 086905ad53 Upate dependencies and saynvanish Repo URL 2025-02-03 14:09:49 +01:00
Andre601 4526e91e0f Add SayanVanish as third-party addon to the docs 2025-02-03 01:19:06 +01:00
Andre601 cfb74b277e Revert updating SayanVanishAPI to 1.6.3 to fix it being fully broken... 2025-02-02 14:40:43 +01:00
Andre601 d7c3a7d756 Merge pull request 'Update all non-major dependencies' (#403) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/403
2025-02-02 12:46:28 +00:00
Andre601's Bot 36c6af0a43 Update all non-major dependencies 2025-02-02 12:03:48 +00:00
Andre601 f9df11c9f8 Add Build ID on Jenkins Builds. 2025-02-01 23:09:38 +01:00
Andre601 8f42b63733 Merge pull request 'Update all non-major dependencies' (#402) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/402
2025-01-31 12:06:35 +00:00
Andre601's Bot 10604f4064 Update all non-major dependencies 2025-01-31 12:03:20 +00:00
Andre601 7a574513af Merge pull request 'Update dependency com.google.code.gson:gson to v2.12.0' (#401) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/401
2025-01-30 12:10:52 +00:00
Andre601's Bot deeea1578d Update dependency com.google.code.gson:gson to v2.12.0 2025-01-30 12:02:28 +00:00
Andre601 ac379b1668 Refactor some stuff 2025-01-30 02:12:04 +01:00
Andre601 c636764f4b Update default config in getting-started.md 2025-01-28 16:13:33 +00:00
Andre601 a823aebafd Exclude kyori in minecraft-extras dependency 2025-01-27 22:37:47 +01:00
Andre601 dd4c3c0eb3 Improve shading of dependencies 2025-01-27 22:32:37 +01:00
Andre601 23afe54e29 No need to use sublist (Is truncated in API) 2025-01-26 02:05:02 +01:00
Andre601 fab3731cf4 Update value change hover 2025-01-26 01:57:01 +01:00
Andre601 49a782d560 Fix broken inherits list for docs 2025-01-25 15:35:00 +00:00
Andre601 cdac325e71 Merge branch 'master' into feature/docs/better-autogen-apidocs 2025-01-25 15:24:16 +00:00
Andre601 88f4278f3f Implement different value types per option 2025-01-25 15:14:06 +01:00
Andre601 de4617e450 Display old and new value on setting 2025-01-24 23:52:41 +01:00
Andre601 4c4573b1e0 Add class to create Options list + /asl profiles set command 2025-01-23 23:39:11 +01:00
Andre601 f74f3ef766 Small restructure 2025-01-22 13:38:51 +01:00
Andre601 806a920d32 Update commands.md 2025-01-22 13:34:38 +01:00
Andre601 c9db8cbc97 Improve info structure a bit 2025-01-22 13:25:06 +01:00
Andre601 3e3cd112ec Change PlayerOnly to CommandType and use enum values 2025-01-22 03:05:53 +01:00
Andre601 fcc7d7c6b6 A loooooooot of work...
Yes, this was absolute pain to make, thanks for asking.
2025-01-22 02:51:15 +01:00
Andre601 cb31fc6f5a Use markdown for entries 2025-01-20 22:11:49 +01:00
Andre601 b26a614f87 Fix issues with Annotationa + add /asl profiles info {profile} 2025-01-20 17:21:35 +01:00
Andre601 eb6f4180bf Implement BungeeCord and Paper Command Handler 2025-01-19 21:13:02 +01:00
Andre601 02d6b1958b Add command alias + remove requiredSender declaration 2025-01-19 19:36:18 +01:00
Andre601 bf3c979819 Use Annotations for commands 2025-01-19 16:49:05 +01:00
Andre601 b5af4b9c47 Use Cloud for Command handling 2025-01-18 23:12:10 +01:00
Andre601 6b9cff2945 Merge pull request 'Update dependency mkdocs-material to v9.5.50' (#399) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/399
2025-01-18 12:16:39 +00:00
Andre601's Bot d17549ee68 Update dependency mkdocs-material to v9.5.50 2025-01-18 12:01:47 +00:00
Andre601 8b73eb3c8c Change PAPI Placeholder behaviour + new placeholders 2025-01-16 02:27:31 +01:00
Andre601 1ee9ae473d Remove api-doc.html 2025-01-13 23:40:04 +01:00
Andre601 37006063cf Add macros plugin to requirements.txt 2025-01-13 23:37:53 +01:00
Andre601 76d97de029 Update API reference pages 2025-01-13 23:36:27 +01:00
Andre601 cd8f6f4c22 Merge branch 'master' into feature/docs/better-autogen-apidocs 2025-01-13 22:32:13 +01:00
Andre601 ce14274e4c Remove PlaceholderAPI page link 2025-01-12 15:34:31 +01:00
Andre601 a5d777f4f1 Restructure Wiki 2025-01-12 15:32:09 +01:00
Andre601 f94e578694 Update formatting.md 2025-01-10 15:28:57 +01:00
Andre601 4ff55ddf28 First work on some templates 2025-01-08 02:13:35 +01:00
Andre601 7c441e6ab5 Update SECURITY.md 2025-01-07 13:36:47 +00:00
Andre601 2779f565a9 Add config option to ignore maintenance for hidePlayersHover 2025-01-06 17:41:37 +01:00
Andre601 6d3cd0c505 Update getting started 2025-01-06 16:33:16 +00:00
Andre601 cf95f11fdb Remove automerge (Useless under current setup) 2025-01-06 15:07:26 +00:00
Andre601 679dbb8c0b Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.16' (#397) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/397
2025-01-06 15:06:29 +00:00
Andre601's Bot f44e2759b9 Update dependency ch.qos.logback:logback-classic to v1.5.16 2025-01-06 12:01:41 +00:00
Andre601 29239cc4ed Add HidePlayersHover to docs 2025-01-05 22:24:16 +01:00
Andre601 bcd5e77166 Try new Bungeecord version to fix CI 2025-01-05 22:02:30 +01:00
Andre601 5d2fa03601 Upload hover examples 2025-01-05 20:39:54 +00:00
Andre601 8f1a5e5a37 Add option to hide online players list. 2025-01-05 20:19:57 +01:00
Andre601 05fde902a4 Merge pull request 'Update dependency space.arim.libertybans:bans-api to v1.1.0-SNAPSHOT' (#395) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/395
2025-01-04 12:18:43 +00:00
Andre601's Bot d69e70c485 Update dependency space.arim.libertybans:bans-api to v1.1.0-SNAPSHOT 2025-01-04 12:16:35 +00:00
Andre601 fba1e84171 Disable dependency Dashboard 2025-01-04 12:15:36 +00:00
Andre601 530f0fd954 Update renovate.json with some automerge and grouping stuff. 2025-01-03 16:06:13 +00:00
Andre601 8bec42bb91 Fix wrong Paper repo URL for renovate 2025-01-03 02:38:41 +00:00
Andre601 94982ff1e8 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.2.1' (#394) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/394
2025-01-02 13:29:51 +00:00
Andre601's Bot 1f9795ed97 Update dependency com.viaversion:viaversion-api to v5.2.1 2025-01-02 12:01:33 +00:00
Andre601 c6f95cb78a Update formatting.md 2024-12-30 13:48:48 +01:00
Andre601 571f9f6b38 Add support for SayanVanish 2024-12-29 01:24:55 +01:00
Andre601 17d0802e41 Add MkDocs Macros Plugin 2024-12-28 16:14:10 +01:00
Andre601 6d7fbb8c25 Merge pull request 'Update API reference' (#393) from feature/update-api-reference into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/393
2024-12-25 00:58:11 +00:00
Andre601 d3d83e5e11 Update ProfileEntry index page 2024-12-25 00:46:43 +00:00
Andre601 82fb9c90f4 Update API reference 2024-12-25 00:39:03 +00:00
Andre601 6841a5a6e0 Undo componentlogger changes on velocity 2024-12-24 22:27:26 +01:00
Andre601 6f41cd4e3a Use a fallback logger for velocity versions without ComponentLoggers 2024-12-24 22:05:56 +01:00
Andre601 379f36832e Use snippet links 2024-12-24 21:45:01 +01:00
Andre601 5d8a39cd22 Update config example in getting-started 2024-12-24 21:43:39 +01:00
Andre601 9dba820840 Reduce flood of messages on Startup + make ASL banner hidable.
(I really don't get why people get upset about a few lines of text... Won't make the Log file like 10GB bigger or smth...)
2024-12-24 21:41:39 +01:00
Andre601 58712ca5c5 Merge pull request 'Update dependency net.kyori:adventure-text-serializer-legacy to v4.18.0' (#392) from renovate/dependency.adventure-text-serializer-legacy into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/392
2024-12-24 12:04:13 +00:00
Andre601's Bot e19e942799 Update dependency net.kyori:adventure-text-serializer-legacy to v4.18.0 2024-12-24 12:01:21 +00:00
Andre601 03434130c4 Update dependency net.kyori:adventure-text-minimessage to v4.18.0 2024-12-23 13:20:48 +01:00
Andre601 99df25551a Merge pull request 'Update dependency net.kyori:adventure-api to v4.18.0' (#390) from renovate/dependency.adventure-api into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/390
2024-12-23 12:14:32 +00:00
Andre601's Bot 4f31e4ce6f Update dependency net.kyori:adventure-api to v4.18.0 2024-12-23 12:01:35 +00:00
Andre601 ba097c538d Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.15' (#389) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/389
2024-12-22 13:03:31 +00:00
Andre601's Bot aa52435591 Update dependency ch.qos.logback:logback-classic to v1.5.15 2024-12-22 12:01:59 +00:00
Andre601 f44194d24f Update docs 2024-12-21 02:21:33 +01:00
Andre601 0e2d760ea6 Upload center_text_example.jpg 2024-12-20 13:31:42 +00:00
Andre601 c1e7e6b3ff Merge pull request 'Add support for centering MOTD lines' (#388) from feature/motd-center-feature into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/388
2024-12-20 13:24:41 +00:00
Andre601 96d383a5a1 Merge branch 'master' into feature/motd-center-feature 2024-12-20 13:24:11 +00:00
Andre601 79ba7877bf Bump version and add docs 2024-12-20 13:46:53 +01:00
Andre601 86b9aaa7c6 Add support for centering MOTD lines 2024-12-20 13:40:11 +01:00
Andre601 0cb3c036af Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.14' (#387) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/387
2024-12-20 12:11:41 +00:00
Andre601's Bot b1f7b75e2d Update dependency ch.qos.logback:logback-classic to v1.5.14 2024-12-20 12:01:15 +00:00
Andre601 e9bc72c165 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.13' (#386) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/386
2024-12-19 12:02:24 +00:00
Andre601's Bot 93203249fe Update dependency ch.qos.logback:logback-classic to v1.5.13 2024-12-19 12:01:11 +00:00
Andre601 2523ccb425 Merge pull request 'Update dependency com.google.guava:guava to v33.4.0-jre' (#384) from renovate/com.google.guava-guava-33.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/384
2024-12-17 12:04:55 +00:00
Andre601 94972dad31 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.4' (#383) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/383
2024-12-17 12:04:39 +00:00
Andre601's Bot f8ac310259 Update dependency com.google.guava:guava to v33.4.0-jre 2024-12-17 12:01:48 +00:00
Andre601's Bot 5d8f5d81ed Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.4 2024-12-17 12:01:40 +00:00
Andre601 3111d7933d Merge pull request 'Move Migration pages to sub-pages' (#382) from docs/move-migration-pages into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/382
2024-12-16 21:42:31 +00:00
Andre601 55f7e17d34 Fix typo. 2024-12-16 21:42:14 +00:00
Andre601 0e88a50deb Move Migration pages to sub-pages 2024-12-16 22:38:55 +01:00
Andre601 83f351de6d Try github.run_number variable 2024-12-16 19:42:19 +00:00
Andre601 b96d1cb1a9 Merge pull request 'Update dependency mkdocs-material to v9.5.49' (#381) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/381
2024-12-16 12:04:47 +00:00
Andre601's Bot 517ff1df82 Update dependency mkdocs-material to v9.5.49 2024-12-16 12:01:18 +00:00
Andre601 e8c7c4ee18 Merge pull request 'Update Wiki Announcement' (#380) from feature/wiki-update-announcement into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/380
2024-12-13 14:15:21 +00:00
Andre601 da44eac70e Fix typos 2024-12-13 14:05:41 +00:00
Andre601 e85c121ee4 Add missing .svg 2024-12-13 13:58:10 +00:00
Andre601 0c175999fc Update announcement 2024-12-13 13:57:32 +00:00
Andre601 9c3f237f6d Use ruby for hocon highlighting 2024-12-11 20:42:52 +01:00
Andre601 777545c94f Possible fix for IndexOutOfBoundsException in condition parsing. 2024-12-10 23:22:41 +01:00
Andre601 dd197609e1 Set secrets via ENV (secrets is deprecated) 2024-12-10 13:29:13 +00:00
Andre601 14ee306463 Bump version 2024-12-10 14:09:34 +01:00
Andre601 a635aa8c91 Merge pull request 'Update dependency net.william278:papiproxybridge to v1.7.2' (#379) from renovate/net.william278-papiproxybridge-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/379
2024-12-09 12:05:22 +00:00
Andre601 050ac3262a Merge pull request 'Update dependency mkdocs-material to v9.5.48' (#378) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/378
2024-12-09 12:05:12 +00:00
Andre601's Bot 89aa309c90 Update dependency net.william278:papiproxybridge to v1.7.2 2024-12-09 12:02:16 +00:00
Andre601's Bot e9b004c3f2 Update dependency mkdocs-material to v9.5.48 2024-12-09 12:02:05 +00:00
Andre601 3ecca64a3d Allow random to be converted in MiniMOTDConfigMigrator 2024-12-09 03:04:22 +01:00
Andre601 96dcea4e5b Fix admonition box 2024-12-08 13:54:35 +00:00
Andre601 400f4709f5 Add missing ! 2024-12-08 13:52:30 +00:00
Andre601 5d4307128b Use thumbnail + link for better privacy 2024-12-08 13:51:44 +00:00
Andre601 65c96690f6 Use youtube-nocookie domain for iframes 2024-12-08 13:44:04 +00:00
Andre601 483d582cd1 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.2.0' (#377) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/377
2024-12-07 12:02:00 +00:00
Andre601's Bot 6f14e17ae7 Update dependency com.viaversion:viaversion-api to v5.2.0 2024-12-07 12:01:26 +00:00
Andre601 ff32cc1005 Use annotation and (hopefully) improve JS code) 2024-12-07 02:03:29 +01:00
Andre601 bcc18d7738 [Wiki] Add tutorials page 2024-12-05 23:51:20 +01:00
Andre601 629079b438 Remove container image (Is now default) 2024-12-05 01:40:04 +00:00
Andre601 bce03b68a8 Remove container image (Is now default) 2024-12-05 01:39:50 +00:00
Andre601 841c32de0d Update docs and smaller corrections 2024-12-04 23:10:50 +01:00
Andre601 f321ef0162 [Wiki] Add info about favicon creation. 2024-12-04 16:42:51 +00:00
Andre601 eca32d1858 Add video of KasaiSora 2024-12-04 16:26:40 +00:00
Andre601 f2c1f6e491 Update favicons description 2024-12-04 16:19:57 +00:00
Andre601 af31aac07e Merge pull request 'Add support for 'random' in Favicon option' (#376) from feature/add-random-favicon-option into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/376
2024-12-01 19:37:49 +00:00
Andre601 f8db3e7706 Add support for 'random' in Favicon option 2024-12-01 17:31:38 +01:00
Andre601 3d3ea2913c Merge pull request 'Create deploy_wiki.yml' (#375) from feature/deploy-wiki-action into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/375
2024-12-01 15:31:07 +00:00
Andre601 7b7042a856 Merge branch 'master' into feature/deploy-wiki-action 2024-12-01 15:30:06 +00:00
Andre601 c66c4f21f3 Ignore tags (releases) 2024-12-01 15:29:01 +00:00
Andre601 890a3f7b46 Create deploy_wiki.yml 2024-12-01 15:24:54 +00:00
Andre601 73b969bc51 Rename preview-domains to preview_domains 2024-12-01 15:22:52 +00:00
Andre601 55c93d8d59 disable publish_docs for woodpecker 2024-12-01 15:14:33 +00:00
Andre601 e1ed8c1cb2 Disable pr_preview for woodpecker 2024-12-01 15:13:50 +00:00
Andre601 e2a91a461a Create pr_preview.yml 2024-12-01 15:12:34 +00:00
Andre601 8a454004a4 Merge pull request 'Update dependency mkdocs-material to v9.5.47' (#374) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/374
2024-12-01 12:05:13 +00:00
Andre601's Bot 8df862530d Update dependency mkdocs-material to v9.5.47 2024-12-01 12:01:41 +00:00
Andre601 4a1c93fb1b Delete build_wiki.yml 2024-11-29 23:11:30 +00:00
Andre601 e795cf31eb Add Git credentials setup 2024-11-29 13:41:05 +00:00
Andre601 e8d93d064f try ubuntu:act-latest from ghcr.io 2024-11-29 13:35:36 +00:00
Andre601 6a2a90b868 Try node:23-alpine.19 2024-11-29 12:53:43 +00:00
Andre601 9cea1d3841 Try ubuntu 20.04? 2024-11-29 12:48:38 +00:00
Andre601 7453b43d6b Try node:22-bookworm 2024-11-28 23:38:13 +00:00
Andre601 7e30f937bd Try using alpine container image 2024-11-28 23:35:56 +00:00
Andre601 176a8ac42e Use a specific python version 2024-11-28 19:36:17 +00:00
Andre601 f480ff51e1 Try out Forgejo Actions 2024-11-28 19:31:12 +00:00
Andre601 e72b772cb9 Add proper highlighting for mitmotd config 2024-11-28 17:04:11 +01:00
Andre601 c91faa899e Add note about availability of BanPlugins Download 2024-11-27 16:34:14 +00:00
Andre601 e5c6d77e3d Merge pull request 'Update dependency mkdocs-material to v9.5.46' (#372) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/372
2024-11-25 12:14:04 +00:00
Andre601's Bot e8ad2c8266 Update dependency mkdocs-material to v9.5.46 2024-11-25 12:03:01 +00:00
Andre601 d244f2816a Merge pull request 'Update dependency mkdocs-material to v9.5.45' (#371) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/371
2024-11-20 12:06:25 +00:00
Andre601's Bot 73f3172504 Update dependency mkdocs-material to v9.5.45 2024-11-20 12:03:20 +00:00
Andre601 d7c9f73898 Fix typo for code block 2024-11-12 01:33:31 +00:00
Andre601 2b6818180f Merge pull request 'Update dependency mkdocs-material to v9.5.44' (#369) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/369
2024-11-06 12:26:39 +00:00
Andre601's Bot c7c14799e3 Update dependency mkdocs-material to v9.5.44 2024-11-06 12:01:46 +00:00
Andre601 59774347f6 Merge pull request 'Update dependency net.william278:papiproxybridge to v1.7.1' (#367) from renovate/net.william278-papiproxybridge-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/367
2024-11-02 12:08:14 +00:00
Andre601 e45f9a1e73 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.1.1' (#368) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/368
2024-11-02 12:07:40 +00:00
Andre601's Bot a44235dc10 Update dependency com.viaversion:viaversion-api to v5.1.1 2024-11-02 12:01:22 +00:00
Andre601's Bot 52569a3588 Update dependency net.william278:papiproxybridge to v1.7.1 2024-11-01 12:01:45 +00:00
Andre601 602a8e27ea Merge pull request 'Update dependency mkdocs-material to v9.5.43' (#366) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/366
2024-10-31 12:14:58 +00:00
Andre601's Bot 81a23953e5 Update dependency mkdocs-material to v9.5.43 2024-10-31 12:01:41 +00:00
Andre601 9daf8f3a3e Delete CHANGELOG.md file 2024-10-30 21:09:21 +00:00
Andre601 3d5b4501e3 Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.1' (#365) from renovate/org.apache.httpcomponents.client5-httpclient5-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/365
2024-10-29 12:09:50 +00:00
Andre601's Bot 67047e9877 Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.1 2024-10-29 12:01:14 +00:00
Andre601 7fcb0e78e3 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.12' (#363) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/363
2024-10-26 12:02:53 +00:00
Andre601 8b8018245e Merge branch 'master' into renovate/ch.qos.logback-logback-classic-1.x 2024-10-26 12:02:40 +00:00
Andre601 b34143d4f5 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.1.0' (#364) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/364
2024-10-26 12:02:25 +00:00
Andre601's Bot a33c096cf4 Update dependency com.viaversion:viaversion-api to v5.1.0 2024-10-26 12:01:27 +00:00
Andre601's Bot 0957edbcd8 Update dependency ch.qos.logback:logback-classic to v1.5.12 2024-10-26 12:01:21 +00:00
Andre601 70adf4e216 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.3' (#361) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/361
2024-10-24 12:10:50 +00:00
Andre601 da42e8c137 Merge pull request 'Update dependency net.william278:papiproxybridge to v1.7' (#362) from renovate/net.william278-papiproxybridge-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/362
2024-10-24 12:10:32 +00:00
Andre601's Bot f4eecda209 Update dependency net.william278:papiproxybridge to v1.7 2024-10-24 12:01:26 +00:00
Andre601's Bot b934d1a856 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.3 2024-10-24 12:01:19 +00:00
Andre601 bbec0aa064 Improve AdvancedBanProvider 2024-10-21 16:43:29 +02:00
Andre601 ba1f620eee SECURITY.md aktualisiert 2024-10-20 22:48:03 +00:00
Andre601 f0281adf8a Merge pull request 'Update dependency mkdocs-material to v9.5.42' (#360) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/360
2024-10-20 12:50:09 +00:00
Andre601's Bot c702f61c21 Update dependency mkdocs-material to v9.5.42 2024-10-20 12:02:03 +00:00
Andre601 dec23e0412 Merge pull request 'Update dependency mkdocs-material to v9.5.41' (#359) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/359
2024-10-16 13:03:17 +00:00
Andre601's Bot 782dcb8382 Update dependency mkdocs-material to v9.5.41 2024-10-16 12:01:17 +00:00
Andre601 e401d1f8c1 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.0.5' (#358) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/358
2024-10-15 13:07:25 +00:00
Andre601 5e6654b3ef Merge branch 'master' into renovate/com.viaversion-viaversion-api-5.x 2024-10-15 13:06:30 +00:00
Andre601 25a9e8ef63 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.11' (#357) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/357
2024-10-15 13:06:16 +00:00
Andre601's Bot 558e47a7da Update dependency com.viaversion:viaversion-api to v5.0.5 2024-10-15 12:02:05 +00:00
Andre601's Bot 740896c304 Update dependency ch.qos.logback:logback-classic to v1.5.11 2024-10-15 12:01:56 +00:00
Andre601 62d9aa81a3 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.10' (#356) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/356
2024-10-12 12:03:19 +00:00
Andre601's Bot 7220b633cf Update dependency ch.qos.logback:logback-classic to v1.5.10 2024-10-12 12:01:33 +00:00
Andre601 0908ddad5e Remove unused imports and bump version 2024-10-10 17:01:10 +02:00
Andre601 d1549b1441 delete release-config.ts 2024-10-10 14:58:51 +00:00
Andre601 57f618e7e2 Remove the action (Pointless and confusing to use) 2024-10-10 14:58:29 +00:00
Andre601 911c64f7ad Merge pull request '🎉 Release 5.0.5' (#352) from next-release/master into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/352
2024-10-10 14:50:32 +00:00
oauth fdeeb35fa9 🎉 Release 5.0.5 2024-10-10 12:30:10 +00:00
oauth c2c653e613 Merge branch 'origin/master' into 'next-release/master' 2024-10-10 12:30:10 +00:00
Andre601 8fa7c1593d Merge pull request 'Update dependency mkdocs-material to v9.5.40' (#355) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/355
2024-10-10 12:29:26 +00:00
Andre601's Bot b2dc74951f Update dependency mkdocs-material to v9.5.40 2024-10-10 12:01:17 +00:00
oauth 099c45e4c4 🎉 Release 5.0.5 2024-10-09 12:29:42 +00:00
oauth e38f6648ee Merge branch 'origin/master' into 'next-release/master' 2024-10-09 12:29:42 +00:00
Andre601 2d701aa8a8 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.9' (#354) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/354
2024-10-09 12:29:05 +00:00
Andre601's Bot 1f32c22ebf Update dependency ch.qos.logback:logback-classic to v1.5.9 2024-10-09 12:01:45 +00:00
oauth 610d86ad1b 🎉 Release 5.0.5 2024-10-09 11:55:51 +00:00
oauth 658ec8dd74 Merge branch 'origin/master' into 'next-release/master' 2024-10-09 11:55:51 +00:00
Andre601 85b7210e7c Push empty commit to trigger release 2024-10-09 13:55:23 +02:00
Andre601 98b99b37de Merge pull request 'Improve PAPIProxyBridge support' (#353) from feature/improve-papi-support into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/353
2024-10-09 11:49:41 +00:00
Andre601 bc3aaa4d28 Improve PAPIProxyBridge support 2024-10-09 13:31:34 +02:00
oauth a3d0342f28 🎉 Release 5.0.5 2024-10-09 11:20:46 +00:00
Andre601 6e057422b6 Merge pull request 'Add automatic release action' (#351) from feature/automatic-release-creation into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/351
2024-10-09 11:20:26 +00:00
Andre601 7ee65c6c21 Add useVersionPrefixV to release-config.ts 2024-10-09 13:18:42 +02:00
Andre601 b4b754e483 Update MODRINTH.md 2024-10-08 23:53:00 +00:00
Andre601 b7c0c8a312 Update Mastodon Link 2024-10-08 23:51:52 +00:00
Andre601 cf6006f9d6 Merge branch 'master' into feature/automatic-release-creation 2024-10-06 00:07:49 +02:00
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 ea0f0f09f4 Add automatic release action 2024-10-02 13:27:46 +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
193 changed files with 6921 additions and 3202 deletions

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
name: "Deploy Wiki"
on:
push:
branches:
- master
tags-ignore:
- "**"
paths:
- ".forgejo/workflows/deploy_wiki.yml"
- "docs/**"
- "domains"
- "mkdocs.yml"
- "requirements.txt"
jobs:
deployWiki:
runs-on: codeberg-tiny
steps:
- name: "Checkout Source Repository"
uses: https://code.forgejo.org/actions/checkout@v4
with:
token: "${{ secrets.BOT_TOKEN }}"
- name: "Checkout Target Repository"
run: "git clone -b pages https://codeberg.org/Andre601/asl-docs site"
- name: "Setup Python 3.x"
uses: https://code.forgejo.org/actions/setup-python@v5
with:
python-version: 3.x
- name: "Install Dependencies"
run: "pip install -r requirements.txt"
- name: "Build Website"
run: "mkdocs build"
- name: "Commit and Push"
run: |
git config --global user.email "andre_601-bot@noreply.codeberg.org"
git config --global user.name "ASL Wiki Builder"
mv domains site/.domains
cd site
git remote set-url origin https://${{ secrets.BOT_TOKEN }}@codeberg.org/Andre601/asl-docs
git add --all
git commit -m "Update Wiki ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" ))"
git push
+116
View File
@@ -0,0 +1,116 @@
name: Pull Request Preview
on:
pull_request_target:
types:
- opened
- reopened
- synchronize
paths:
- ".forgejo/workflows/pr_preview.yml"
- "docs/**"
- "mkdocs.yml"
- "preview_domains"
- "requirements.txt"
workflow_dispatch:
env:
BRANCH_NAME: "${{ github.event.repository.name }}/${{ github.event.pull_request.number }}"
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}"
jobs:
createPreview:
runs-on: codeberg-tiny
steps:
#
# Finding and updating comment in Pull request.
# If not found, have one created instead.
#
- name: "Find Comment"
id: find-comment
uses: https://github.com/peter-evans/find-comment@v3
with:
issue-number: "${{ github.event.pull_request.number }}"
comment-author: "Andre_601-Bot"
- name: "Create or update Comment"
id: comment
uses: https://github.com/peter-evans/create-or-update-comment@v4
with:
body: |-
## Pull request Preview
Creating Preview for Pull request. Please wait...
comment-id: "${{ steps.find-comment.outputs.comment-id }}"
issue-number: "${{ github.event.pull_request.number }}"
token: "${{ secrets.BOT_TOKEN }}"
edit-mode: replace
#
# Setup source and target repository.
# Build website and push.
#
- name: "Checkout Source Repository"
uses: https://code.forgejo.org/actions/checkout@v4
with:
token: ${{ secrets.BOT_TOKEN }}
fetch-depth: 0
ref: "${{ github.event.pull_request.head.sha }}"
- name: "Checkout Target Repository"
run: |
git clone https://codeberg.org/Andre601/preview site
cd site
git switch ${{ env.BRANCH_NAME }} 2>/dev/null || git switch -c ${{ env.BRANCH_NAME }}
- name: "Setup Python 3.x"
uses: https://code.forgejo.org/actions/setup-python@v5
with:
python-version: 3.x
- name: "Install Dependencies"
run: "pip install -r requirements.txt"
- name: "Build Website"
run: "mkdocs build"
- name: "Commit and Push"
run: |
git config --global user.email "andre_601-bot@noreply.codeberg.org"
git config --global user.name "PR Docs Preview Builder"
mv preview_domains site/.domains
cd site
git remote add upstream https://${{ secrets.BOT_TOKEN }}@codeberg.org/Andre601/preview.git
git add --all
git commit -m "Update Preview for ${{ env.BRANCH_NAME }} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" ))"
git push --set-upstream upstream ${{ env.BRANCH_NAME }} -f
#
# Update comment on success or failure.
#
- name: "Comment Success"
uses: https://github.com/peter-evans/create-or-update-comment@v4
with:
body: |-
## Pull request Preview
Pull request Preview created successfully!
| Name | Link |
|---------|----------------------------------------------------------------------------------------------------------|
| Commit | ${{ github.event.pull_request.head.sha }} |
| Preview | https://preview.andre601.ch/@${{ github.event.repository.name }}~${{ github.event.pull_request.number }} |
| Logs | ${{ env.RUN_URL }} |
comment-id: "${{ steps.comment.outputs.comment-id }}"
issue-number: "${{ github.event.pull_request.number }}"
token: "${{ secrets.BOT_TOKEN }}"
edit-mode: replace
- name: "Comment Failure"
if: ${{ failure() }}
uses: https://github.com/peter-evans/create-or-update-comment@v4
with:
body: |-
## Pull request Preview
Pull request Preview failed! Check the logs for details.
| Name | Link |
|---------|-------------------------------------------|
| Commit | ${{ github.event.pull_request.head.sha }} |
| Logs | ${{ RUN_URL }} |
comment-id: "${{ steps.comment.outputs.comment-id }}"
issue-number: "${{ github.event.pull_request.number }}"
token: "${{ secrets.BOT_TOKEN }}"
edit-mode: replace
+54 -59
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>
<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
<br>
<a href="https://swiss.social/@andre_601" target="_blank">
<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: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 KiB

@@ -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:
+9 -7
View File
@@ -4,21 +4,23 @@ when:
steps:
- name: "Build Jar and Upload"
image: maven:3.9.6-eclipse-temurin-17
secrets:
- modrinth_api_token
- hangar_api_token
- discord_webhook_url
image: maven:3.9.10-eclipse-temurin-21
environment:
CODEBERG_API_TOKEN:
from_secret: cb_token
MODRINTH_API_TOKEN:
from_secret: modrinth_api_token
HANGAR_API_TOKEN:
from_secret: hangar_api_token
DISCORD_WEBHOOK_URL:
from_secret: discord_webhook_url
commands:
- mvn clean install
- cd version-uploader/target
- mv VersionUploader.jar ../../
- cd ../../
- java -jar VersionUploader.jar --all
- name: "Upload Jars to Codeber"
- name: "Upload Jars to Codeberg"
image: woodpeckerci/plugin-gitea-release
settings:
base_url: https://codeberg.org
@@ -34,7 +36,7 @@ steps:
when:
- status: ["success"]
settings:
server_url: https://blobfox.coffee
server_url: https://swiss.social
access_token:
from_secret: mastodon_token
status: |-
@@ -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:
+67 -64
View File
@@ -1,119 +1,122 @@
# 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/options/priority) and [Conditions](https://asl.andre601.ch/profiles/options/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>
English Video by KasaiSora
[![video thumbnail](https://img.youtube.com/vi/9cU0uUWHOO0/0.jpg)](https://youtube.com/watch?v=9cU0uUWHOO0)
Spanish Video by Ajneb97
[![video thumbnail](https://img.youtube.com/vi/rIbljm_4HVI/0.jpg)](https://youtube.com/watch?v=rIbljm_4HVI)
Indonesian Video by faajrikha
[![video thumbnail](https://img.youtube.com/vi/-p938rOmqy4/0.jpg)](https://www.youtube.com/watch?v=-p938rOmqy4)
German Video by Finni Gamer
[![video thumbnail](https://img.youtube.com/vi/1Kh3cPMDd0c/0.jpg)](https://www.youtube.com/watch?v=1Kh3cPMDd0c)
</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>
<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
<br>
<a href="https://swiss.social/@andre_601" target="_blank">
<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>
+60
View File
@@ -0,0 +1,60 @@
# 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 |
|---------------|-----------|
| v5 | Yes |
| v4 | Yes* |
| v3 | No** |
| v2 | No |
| v1 | No |
\*Only receives support but no updates or bug fixes.
\*\*Support ended on December 31st, 2024.
## 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.
+9 -16
View File
@@ -40,8 +40,8 @@
<version>${plugin.version}</version>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@@ -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>
@@ -65,21 +65,21 @@
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2</version>
<version>1.21-R0.3</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2</version>
<version>1.21-R0.3</version>
<type>javadoc</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.21-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -99,13 +99,13 @@
<dependency>
<groupId>space.arim.libertybans</groupId>
<artifactId>bans-api</artifactId>
<version>1.1.0-RC1</version>
<version>1.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.gitlab.ruany</groupId>
<artifactId>LiteBansAPI</artifactId>
<version>0.5.0</version>
<version>0.6.1</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -117,19 +117,12 @@
</dependencies>
<build>
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}</finalName>
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}${project.build.build_id}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
</plugins>
</build>
</project>
@@ -47,7 +47,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
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)
@@ -64,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)
@@ -47,7 +47,7 @@ public class LibertyBansPlaceholders extends PlaceholderProvider{
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)
@@ -57,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)
@@ -52,8 +52,9 @@ public class LiteBansPlaceholders extends PlaceholderProvider{
CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->
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" -> provider.muteDuration(player);
case "muteExpiration" -> {
if(args.length == 1)
yield provider.muteExpirationDate(player);
@@ -62,8 +63,9 @@ public class LiteBansPlaceholders extends PlaceholderProvider{
}
// Ban-related placeholders
case "isBanned" -> String.valueOf(provider.banned(player));
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);
@@ -31,40 +31,18 @@ import com.google.common.primitives.UnsignedLongs;
import me.leoko.advancedban.manager.PunishmentManager;
import me.leoko.advancedban.utils.Punishment;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
public class AdvancedBanProvider implements PunishmentProvider{
private static PunishmentManager getAPI(){
return PunishmentManager.get();
}
private static String noDashesUUID(UUID uuid){
return hexString(uuid.getMostSignificantBits()) + hexString(uuid.getLeastSignificantBits());
}
private static Punishment mute(GenericPlayer player){
return getAPI().getMute(noDashesUUID(player.getUUID()));
}
private static Punishment ban(GenericPlayer player){
return getAPI().getBan(noDashesUUID(player.getUUID()));
}
private static String hexString(long unsigned){
return Strings.padStart(UnsignedLongs.toString(unsigned, 16), 16, '0');
@Override
public String muted(GenericPlayer player){
return String.valueOf(getAPI().isMuted(noDashesUUID(player.getUUID())));
}
@Override
public boolean muted(GenericPlayer player){
return 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
@@ -136,4 +114,24 @@ public class AdvancedBanProvider implements PunishmentProvider{
return ban.getDuration(fromStart);
}
private PunishmentManager getAPI(){
return PunishmentManager.get();
}
private String noDashesUUID(UUID uuid){
return hexString(uuid.getMostSignificantBits()) + hexString(uuid.getLeastSignificantBits());
}
private Punishment mute(GenericPlayer player){
return getAPI().getMute(noDashesUUID(player.getUUID()));
}
private Punishment ban(GenericPlayer player){
return getAPI().getBan(noDashesUUID(player.getUUID()));
}
private String hexString(long unsigned){
return Strings.padStart(UnsignedLongs.toString(unsigned, 16), 16, '0');
}
}
@@ -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
@@ -32,13 +32,13 @@ import litebans.api.Entry;
public class LiteBansProvider implements PunishmentProvider{
@Override
public boolean muted(GenericPlayer player){
return Database.get().isPlayerMuted(player.getUUID(), null);
public String muted(GenericPlayer player){
return String.valueOf(Database.get().isPlayerMuted(player.getUUID(), null));
}
@Override
public boolean banned(GenericPlayer player){
return Database.get().isPlayerBanned(player.getUUID(), null);
public String banned(GenericPlayer player){
return String.valueOf(Database.get().isPlayerBanned(player.getUUID(), null));
}
@Override
@@ -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);
@@ -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,7 +11,7 @@ dependencies:
AdvancedServerList:
required: false
load: BEFORE
AdvancedBans:
AdvancedBan:
required: false
load: BEFORE
LibertyBans:
+65 -39
View File
@@ -40,8 +40,9 @@
<description>${plugin.description}</description>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
@@ -50,8 +51,8 @@
<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>
<id>repo-sayandevelopment</id>
<url>https://repo.sayandev.org/releases/</url>
</repository>
</repositories>
@@ -73,19 +74,19 @@
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2</version>
<version>1.21-R0.3</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2</version>
<version>1.21-R0.3</version>
<type>javadoc</type>
<scope>provided</scope>
</dependency>
<!-- Adventure Library. Needs to be shaded in -->
<!-- Adventure Library -->
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
@@ -109,7 +110,7 @@
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bungeecord</artifactId>
<version>3.0.2</version>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
@@ -125,7 +126,19 @@
<dependency>
<groupId>com.github.LeonMangler</groupId>
<artifactId>PremiumVanishAPI</artifactId>
<version>2.9.0-4</version>
<version>2.9.18-2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-api</artifactId>
<version>1.6.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-proxy-bungeecord</artifactId>
<version>1.6.5</version>
<scope>provided</scope>
</dependency>
@@ -136,10 +149,16 @@
<version>2.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.incendo</groupId>
<artifactId>cloud-bungee</artifactId>
<version>${dependency.cloud-bungee}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>AdvancedServerList-BungeeCord-${plugin.version}</finalName>
<finalName>AdvancedServerList-BungeeCord-${plugin.version}${project.build.build_id}</finalName>
<resources>
<resource>
<filtering>true</filtering>
@@ -147,44 +166,51 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>net.byteflux.libby</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.libby</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.alessiodp.libby</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.libby</shadedPattern>
</relocation>
<relocation>
<pattern>ch.andre601.expressionparser</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.expressionparser</shadedPattern>
</relocation>
<relocation>
<pattern>com.unascribed.flexver</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.flexver</shadedPattern>
</relocation>
<relocation>
<pattern>org.incendo.cloud</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.cloud</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
@@ -25,48 +25,64 @@
package ch.andre601.advancedserverlist.bungeecord;
import ch.andre601.advancedserverlist.bungeecord.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.bungeecord.listeners.JoinEvent;
import ch.andre601.advancedserverlist.bungeecord.listeners.PingEvent;
import ch.andre601.advancedserverlist.bungeecord.commands.BungeeCommandManagerInterface;
import ch.andre601.advancedserverlist.bungeecord.listeners.PlayerJoinEventListener;
import ch.andre601.advancedserverlist.bungeecord.listeners.ProxyPingEventListener;
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.commands.CmdSender;
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;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import org.incendo.cloud.CommandManager;
import org.sayandev.sayanvanish.bungeecord.api.SayanVanishBungeeAPI;
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;
import java.util.logging.Level;
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 BungeeCommandManagerInterface handler;
private BungeeLibraryManager libraryManager = null;
@Override
public void onLoad(){
logger.info("Loading libraries. This may take a while...");
// Using getLogger() here, because PluginLogger requires MiniMessage, which isn't loaded at this stage.
getLogger().info("Loading libraries. This may take a while...");
successfulLoad = loadLibs();
if(successfulLoad){
logger.info("Library loading completed successfully!");
getLogger().info("Library loading completed successfully!");
}else{
logger.warn("Library loading completed with errors!");
getLogger().warning("Library loading completed with errors!");
}
}
@@ -74,28 +90,27 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
public void onEnable(){
if(!successfulLoad){
logger.warn("There were issues during the plugins Loading-phase! Please see the console for possible reasons.");
logger.warn("The plugin won't be enabled to avoid problems.");
logger.warn("Aborting further enabling of the plugin to avoid errors.");
return;
}
this.audiences = BungeeAudiences.create(this);
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this));
this.handler = new BungeeCommandManagerInterface(this);
this.core = AdvancedServerList.init(this,
BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this), BungeeProxyPlaceholders.init(this));
}
@Override
public void onDisable(){
core.disable();
}
@Override
public void loadCommands(){
getProxy().getPluginManager().registerCommand(this, new CmdAdvancedServerList(this));
getProxy().getScheduler().cancel(this);
audiences.close();
}
@Override
public void loadEvents(){
new JoinEvent(this);
new PingEvent(this);
new PlayerJoinEventListener(this);
new ProxyPingEventListener(this);
}
@Override
@@ -119,6 +134,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 +180,13 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
}
@Override
public String getPlatformName(){
return getProxy().getName();
public CommandManager<CmdSender> getCommandManager(){
return handler.commandHandler();
}
@Override
public String getPlatformVersion(){
return getProxy().getVersion();
public String getPlatformInfo(){
return getProxy().getName() + " " + getProxy().getVersion();
}
@Override
@@ -177,20 +214,41 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
// Exclude players when PremiumVanish is enabled and player is hidden.
if(getProxy().getPluginManager().getPlugin("PremiumVanish") != null){
players.removeIf(BungeeVanishAPI::isInvisible);
}else // Do the same if SayanVanish is enabled.
if(getProxy().getPluginManager().getPlugin("SayanVanish") != null){
players.removeIf(player -> SayanVanishBungeeAPI.getInstance().isVanished(player.getUniqueId()));
}
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;
}catch(Exception ex){
logger.warn("Encountered an Exception while trying to load dependencies.", ex);
getLogger().log(Level.WARNING, "Encountered an Exception while trying to load dependencies.", ex);
return false;
}
}
private void fetchServers(){
fetchedServers.clear();
getProxy().getServers().forEach((name, server) -> server.ping((ping, throwable) -> {
if(throwable != null)
return;
fetchedServers.put(name, ping);
}));
}
}
@@ -27,8 +27,10 @@ package ch.andre601.advancedserverlist.bungeecord.commands;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
public class BungeeCmdSender implements CmdSender{
@@ -40,13 +42,22 @@ public class BungeeCmdSender implements CmdSender{
this.bungeeAudiences = bungeeAudiences;
}
@Override
public boolean hasPermission(String permission){
return sender.hasPermission(permission) || sender.hasPermission("advancedserverlist.admin");
}
@Override
public void sendMsg(String msg, Object... args){
bungeeAudiences.sender(sender).sendMessage(ComponentParser.text(String.format(msg, args)).toComponent());
}
@Override
public Audience audience(){
return bungeeAudiences.sender(sender);
}
@Override
public boolean isPlayer(){
return sender instanceof ProxiedPlayer;
}
public CommandSender sender(){
return sender;
}
}
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
* Copyright (c) 2022-2025 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
@@ -20,27 +20,41 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord.commands;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandManagerInterface;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.SenderMapper;
import org.incendo.cloud.bungee.BungeeCommandManager;
import org.incendo.cloud.execution.ExecutionCoordinator;
public class CmdAdvancedServerList extends Command{
public class BungeeCommandManagerInterface implements CommandManagerInterface<CommandSender>{
private final BungeeCordCore plugin;
public CmdAdvancedServerList(BungeeCordCore plugin){
super("advancedserverlist", "advancedserverlist.command.asl", "asl");
public BungeeCommandManagerInterface(BungeeCordCore plugin){
this.plugin = plugin;
}
@Override
public void execute(CommandSender sender, String[] args){
plugin.getCore().getCommandHandler().handle(new BungeeCmdSender(sender, plugin.getAudiences()), args);
public CommandManager<CmdSender> commandHandler(){
return new BungeeCommandManager<>(
plugin,
ExecutionCoordinator.asyncCoordinator(),
senderMapper()
);
}
@Override
public SenderMapper<CommandSender, CmdSender> senderMapper(){
return SenderMapper.create(
cmdSender -> new BungeeCmdSender(cmdSender, plugin.getAudiences()),
sender -> ((BungeeCmdSender)sender).sender()
);
}
}
@@ -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());
@@ -111,6 +118,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
ping.getPlayers().setSample(players);
}
@Override
public void setPlayersHidden(){
ping.getPlayers().setSample(new ServerPing.PlayerInfo[0]);
}
@Override
public void setFavicon(Favicon favicon){
ping.setFavicon(favicon);
@@ -137,7 +149,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 +177,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 +188,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
@@ -34,10 +34,10 @@ import net.md_5.bungee.event.EventHandler;
import java.net.InetSocketAddress;
public class JoinEvent implements Listener{
public class PlayerJoinEventListener implements Listener{
private final BungeeCordCore plugin;
public JoinEvent(BungeeCordCore plugin){
public PlayerJoinEventListener(BungeeCordCore plugin){
this.plugin = plugin;
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@@ -33,11 +33,11 @@ import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class PingEvent implements Listener{
public class ProxyPingEventListener implements Listener{
private final BungeeCordCore plugin;
public PingEvent(BungeeCordCore plugin){
public ProxyPingEventListener(BungeeCordCore plugin){
this.plugin = plugin;
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@@ -27,6 +27,7 @@ package ch.andre601.advancedserverlist.bungeecord.logging;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -55,21 +56,21 @@ public class BungeeLogger implements PluginLogger{
@Override
public void info(String msg, Object... args){
logger.info(String.format(msg, args));
logger.info(ComponentParser.textFormatted(msg, args).toStringStriped());
}
@Override
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
logger.warning(ComponentParser.textFormatted(msg, args).toStringStriped());
}
@Override
public void warn(String msg, Throwable throwable){
logger.log(Level.WARNING, msg, throwable);
logger.log(Level.WARNING, ComponentParser.text(msg).toStringStriped(), throwable);
}
@Override
public void warn(String msg, Throwable throwable, Object... args){
logger.log(Level.WARNING, String.format(msg, args), throwable);
logger.log(Level.WARNING, ComponentParser.textFormatted(msg, args).toStringStriped(), throwable);
}
}
@@ -25,14 +25,25 @@
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 record BungeePlayerImpl(CachedPlayer player, int protocol) implements BungeePlayer{
public BungeePlayerImpl(CachedPlayer player, int protocol){
this.name = player.name();
this.protocol = protocol;
this.uuid = player.uuid();
@Override
public String getName(){
return player.name();
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return player.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",
+61 -45
View File
@@ -39,9 +39,11 @@
<version>${plugin.version}</version>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<plugin.config.version>5</plugin.config.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plugin.config.version>9</plugin.config.version>
</properties>
<repositories>
@@ -77,15 +79,23 @@
<dependency>
<groupId>ch.andre601</groupId>
<artifactId>expressionparser</artifactId>
<version>1.4.2</version>
<version>1.6.0</version>
<scope>compile</scope>
</dependency>
<!-- Configuration -->
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<version>${dependency.configurate-yaml}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-hocon</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
<!-- MiniMessage -->
<dependency>
@@ -111,7 +121,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<version>2.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -123,21 +133,48 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version>
<version>33.4.8-jre</version>
<scope>provided</scope>
</dependency>
<!-- Command Framework -->
<dependency>
<groupId>org.incendo</groupId>
<artifactId>cloud-annotations</artifactId>
<version>${dependency.cloud-annotations}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.incendo</groupId>
<artifactId>cloud-minecraft-extras</artifactId>
<version>${dependency.cloud-minecraft-extras}</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>net.kyori</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Annotations -->
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Plugins -->
<dependency>
<groupId>net.william278</groupId>
<artifactId>papiproxybridge</artifactId>
<version>1.6.1</version>
<version>1.8.1</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,60 +188,39 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
<version>5.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>AdvancedServerList-Core-${plugin.version}</finalName>
<finalName>AdvancedServerList-Core-${plugin.version}${project.build.build_id}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
<excludes>
<exclude>char-widths.json.gz</exclude>
</excludes>
</resource>
<resource>
<filtering>false</filtering>
<directory>${project.basedir}/src/main/resources</directory>
<includes>
<include>char-widths.json.gz</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.14.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>com.unascribed</pattern>
<shadedPattern>ch.andre601.advancedserverlist.core.depends.flexver</shadedPattern>
</relocation>
<relocation>
<pattern>ch.andre601.expressionparser</pattern>
<shadedPattern>ch.andre601.advancedserverlist.core.depends.expressionparser</shadedPattern>
</relocation>
</relocations>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@@ -29,23 +29,45 @@ 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.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.TextCenterUtil;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
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 org.incendo.cloud.CommandManager;
import org.incendo.cloud.annotations.AnnotationParser;
import org.incendo.cloud.description.Description;
import org.incendo.cloud.injection.ParameterInjector;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.parser.standard.BooleanParser;
import org.incendo.cloud.parser.standard.IntegerParser;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.permission.Permission;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
public class AdvancedServerList<F>{
public static <F> AdvancedServerList<F> init(PluginCore<F> plugin, PlaceholderProvider... placeholders){
return new AdvancedServerList<>(plugin, Arrays.asList(placeholders));
}
private final PluginCore<F> plugin;
private final FileHandler fileHandler;
private final CommandHandler commandHandler;
private final PlayerHandler playerHandler;
private final TextCenterUtil textCenterUtil;
private static final AdvancedServerListAPI api = AdvancedServerListAPI.get();
private final ProfileConditionParser parser = ProfileConditionParser.create();
@@ -56,16 +78,24 @@ public class AdvancedServerList<F>{
private AdvancedServerList(PluginCore<F> plugin, List<PlaceholderProvider> placeholders){
this.plugin = plugin;
this.fileHandler = new FileHandler(this);
this.commandHandler = new CommandHandler(this);
this.playerHandler = new PlayerHandler(this);
this.textCenterUtil = new TextCenterUtil(this);
placeholders.forEach(AdvancedServerList.getApi()::addPlaceholderProvider);
plugin.getPluginLogger().info("Registering internal Placeholders...");
placeholders.forEach(this::addPlaceholder);
if(plugin.isPluginEnabled("Maintenance")){
addPlaceholder(new MaintenancePlaceholder(this));
}
resolveVersion();
getPlugin().getPluginLogger().info("Starting <white>AdvancedServerList v%s</white>...", version);
load();
}
public static <F> AdvancedServerList<F> init(PluginCore<F> plugin, PlaceholderProvider... placeholders){
return new AdvancedServerList<>(plugin, Arrays.asList(placeholders));
public static AdvancedServerListAPI getApi(){
return api;
}
public PluginCore<F> getPlugin(){
@@ -76,10 +106,6 @@ public class AdvancedServerList<F>{
return fileHandler;
}
public CommandHandler getCommandHandler(){
return commandHandler;
}
public PlayerHandler getPlayerHandler(){
return playerHandler;
}
@@ -88,10 +114,6 @@ public class AdvancedServerList<F>{
return version;
}
public static AdvancedServerListAPI getApi(){
return api;
}
public ProfileConditionParser getParser(){
return parser;
}
@@ -100,16 +122,20 @@ public class AdvancedServerList<F>{
return updateChecker;
}
public TextCenterUtil getTextCenterUtil(){
return textCenterUtil;
}
public void disable(){
getPlugin().getPluginLogger().info("Saving playercache.json file...");
getPlugin().getPluginLogger().info("[-] Saving <white>playercache.json</white> file...");
getPlayerHandler().save();
if(updateChecker != null){
getPlugin().getPluginLogger().info("Disabling Update Checker...");
getPlugin().getPluginLogger().info("[-] Disabling Update Checker...");
updateChecker.disable();
}
getPlugin().getPluginLogger().info("AdvancedServerList disabled!");
getPlugin().getPluginLogger().success("AdvancedServerList disabled!");
}
public void clearFaviconCache(){
@@ -121,67 +147,58 @@ public class AdvancedServerList<F>{
}
private void load(){
printBanner();
resolveVersion();
getPlugin().getPluginLogger().info("Starting AdvancedServerList v%s...", version);
getPlugin().getPluginLogger().info("Platform: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
if(getFileHandler().loadConfig()){
getPlugin().getPluginLogger().info("Successfully loaded config.yml!");
}else{
getPlugin().getPluginLogger().warn("Unable to load config.yml! Check previous lines for errors.");
if(!getFileHandler().loadConfig()){
getPlugin().getPluginLogger().failure("Unable to load <white>config.yml</white>! Check previous lines for errors.");
return;
}
if(getFileHandler().isOldConfig()){
getPlugin().getPluginLogger().info("Detected old config.yml. Attempting to migrate...");
getPlugin().getPluginLogger().info("[-] Detected old <white>config.yml</white>. Attempting to migrate...");
if(getFileHandler().migrateConfig()){
getPlugin().getPluginLogger().info("Migration completed successfully!");
getPlugin().getPluginLogger().success("Migration completed successfully!");
}else{
getPlugin().getPluginLogger().warn("Couldn't migrate config.yml! Check previous lines for errors.");
getPlugin().getPluginLogger().failure("Couldn't migrate <white>config.yml</white>! Check previous lines for errors.");
return;
}
}
if(getFileHandler().getBool(true, "printBanner")){
printBanner();
}
getPlugin().getPluginLogger().info("Platform: <white>%s</white>", plugin.getPlatformInfo());
getPlugin().getPluginLogger().info("");
if(getFileHandler().loadProfiles()){
getPlugin().getPluginLogger().info("Successfully loaded %d profile(s)!", getFileHandler().getProfiles().size());
getPlugin().getPluginLogger().success("Successfully loaded <white>%d</white> profile(s)!", getFileHandler().getProfiles().size());
}else{
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
getPlugin().getPluginLogger().failure("Unable to load profiles! Check previous lines for errors.");
return;
}
getPlugin().loadFaviconHandler(this);
getPlugin().getPluginLogger().info("Loading Commands...");
plugin.loadCommands();
getPlugin().getPluginLogger().info("Commands loaded!");
getPlugin().getPluginLogger().info("Loading events...");
loadCommands();
plugin.loadEvents();
getPlugin().getPluginLogger().info("Events loaded!");
getPlugin().getPluginLogger().info("Loading playercache.json...");
getPlayerHandler().load();
getPlugin().getPluginLogger().info("Loading bStats metrics. Disable it in the global config under /plugins/bstats/");
plugin.loadMetrics();
getPlugin().getPluginLogger().info("Metrics loaded!");
plugin.startScheduler();
getPlugin().getPluginLogger().info("AdvancedServerList is ready!");
getPlugin().getPluginLogger().success("<green>AdvancedServerList is ready!");
if(getFileHandler().getBoolean("checkUpdates"))
this.updateChecker = new UpdateChecker(this);
}
private void printBanner(){
getPlugin().getPluginLogger().info(" _____ _");
getPlugin().getPluginLogger().info(" /\\ / ____| |");
getPlugin().getPluginLogger().info(" / \\ | (___ | |");
getPlugin().getPluginLogger().info(" / /\\ \\ \\___ \\| |");
getPlugin().getPluginLogger().info(" / ____ \\ ____) | |____");
getPlugin().getPluginLogger().info("/_/ \\_\\_____/|______|");
getPlugin().getPluginLogger().info("<#3b90ff> __ _______ ___");
getPlugin().getPluginLogger().info("<#3b90ff> /\\ \\ / ____|_| | |");
getPlugin().getPluginLogger().info("<#3b90ff> / \\ \\ | (_(___ | | |");
getPlugin().getPluginLogger().info("<#3b90ff> / /\\ \\ \\ \\___ \\ \\| | |");
getPlugin().getPluginLogger().info("<#3b90ff> / ____ \\ \\ ____) | | |_|____");
getPlugin().getPluginLogger().info("<#3b90ff>/_/_/ \\_\\_\\_____/_/|______|_|");
getPlugin().getPluginLogger().info("");
seasonalText();
}
private void resolveVersion(){
@@ -195,4 +212,119 @@ public class AdvancedServerList<F>{
version = "UNKNOWN";
}
}
private void addPlaceholder(PlaceholderProvider placeholderProvider){
AdvancedServerList.getApi().addPlaceholderProvider(placeholderProvider);
}
private void loadCommands(){
getPlugin().loadFaviconHandler(this);
CommandManager<CmdSender> commandManager = plugin.getCommandManager();
commandManager.parameterInjectorRegistry().registerInjector(AdvancedServerList.class, ParameterInjector.constantInjector(this));
AnnotationParser<CmdSender> annotationParser = new AnnotationParser<>(commandManager, CmdSender.class);
annotationParser.registerBuilderModifier(
CommandType.class,
(annotation, builder) -> builder.meta(CommandHandler.COMMAND_TYPE, annotation.value())
);
annotationParser.parse(new CommandHandler(commandManager));
for(String option : CommandHandler.PROFILE_OPTIONS){
commandManager.command(
commandManager.commandBuilder("advancedserverlist", "asl")
.literal("profiles")
.literal("set")
.required(
"profile",
StringParser.stringParser(),
Description.of("The profile to edit."),
SuggestionProvider.suggesting(
getFileHandler().getProfiles().stream()
.map(ServerListProfile::file)
.map(Suggestion::suggestion)
.toList()
)
)
.literal(option)
.optional("value", descriptor(option), description(option))
.commandDescription(Description.of("Sets or resets profile values."))
.handler(context -> CommandHandler.handleSet(this, context))
.meta(CommandHandler.OPTION, option)
.permission(
Permission.anyOf(
Permission.permission("advancedserverlist.admin"),
Permission.permission("advancedserverlist.command.profiles"),
Permission.permission("advancedserverlist.command.profiles.set")
)
)
);
}
getPlugin().getPluginLogger().success("Loaded Command <white>/advancedserverlist</white>!");
}
private ParserDescriptor<CmdSender, ?> descriptor(String option){
return switch(option){
case "playercount.hideplayers", "playercount.hideplayershover", "playercount.extraplayers.enabled",
"playercount.maxplayers.enabled", "playercount.onlineplayers.enabled" -> BooleanParser.booleanParser();
case "priority" -> IntegerParser.integerParser();
default -> StringParser.greedyStringParser();
};
}
private Description description(String option){
return switch(option){
case "playercount.hideplayers", "playercount.hideplayershover", "playercount.extraplayers.enabled",
"playercount.maxplayers.enabled", "playercount.onlineplayers.enabled" -> Description.of(
"Whether this option should be enabled or not. Leave empty to unset it."
);
case "priority" -> Description.of("Priority this Profile should have. Leave empty to reset.");
case "motd", "playercount.hover" -> Description.of(
"Lines to set. Use \\n or <newline> to set a linebreak. Leave empty to reset."
);
default -> Description.of("The Value to use for this option. Leave empty to reset.");
};
}
// Adding some seasonal messages
private void seasonalText(){
LocalDate date = LocalDate.now();
switch(date.getMonth()){
case JANUARY -> {
if(date.getDayOfMonth() == 1){
getPlugin().getPluginLogger().info("Happy new Year!");
getPlugin().getPluginLogger().info("");
}
}
case JUNE -> {
getPlugin().getPluginLogger().info("Happy Pride Month!");
getPlugin().getPluginLogger().info("");
}
case AUGUST -> {
if(date.getDayOfMonth() == 1){
getPlugin().getPluginLogger().info("Happy Birthday Switzerland!");
getPlugin().getPluginLogger().info("");
}
}
case OCTOBER -> {
if(date.getDayOfMonth() == 31){
getPlugin().getPluginLogger().info("Happy Halloween!");
getPlugin().getPluginLogger().info("");
}
}
case DECEMBER -> {
if(date.getDayOfMonth() == 13){
getPlugin().getPluginLogger().info("Happy Birthday Andre_601!");
getPlugin().getPluginLogger().info("");
}else
if(date.getDayOfMonth() > 23 && date.getDayOfMonth() < 27){
getPlugin().getPluginLogger().info("Merry Christmas!");
getPlugin().getPluginLogger().info("");
}
}
}
}
}
@@ -28,7 +28,7 @@ package ch.andre601.advancedserverlist.core.check;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.objects.CacheUtil;
import ch.andre601.advancedserverlist.core.objects.ValueCache;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -51,57 +51,64 @@ 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 ValueCache<CompletableFuture<ModrinthVersion>> cache = new ValueCache<>(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(
"Your version (<white>%</white>) is newer than what is available on Modrinth (<white>%s</white>).",
core.getVersion(),
version.versionNumber()
);
sender.sendPrefixedMsg("Are you using a Development Version?");
}
});
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(){
@@ -120,11 +127,11 @@ public class UpdateChecker{
private void startUpdateChecker(){
executor.scheduleAtFixedRate(() -> {
logger.info("Looking for an update...");
logger.info("[-] Looking for an update...");
performUpdateCheck().whenComplete((version, throwable) -> {
if(version == null || throwable != null){
logger.warn("Failed to look for any updates. Check previous messages for causes.");
logger.failure("Failed to look for any updates. Check previous messages for causes.");
return;
}
@@ -133,18 +140,26 @@ public class UpdateChecker{
int result = version.compare(core.getVersion());
switch(result){
case -1 -> printUpdateBanner(version);
case 0 -> logger.info("You are running the latest version!");
case 1 -> logger.info(
"Your version (%s) seems to be newer than the latest release (%s). Are you running a dev build?",
core.getVersion(), version.versionNumber()
);
case 0 -> logger.success("You are running the latest version!");
case 1 -> {
logger.info(
"[?] Your version (<white>%s</white>) is newer than what is available on Modrint (<white>%s</white>).",
core.getVersion(),
version.versionNumber()
);
logger.info(" Are you using a Development Version?");
}
}
});
}, 0L, 12L, TimeUnit.HOURS);
}
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 +172,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){
@@ -177,18 +193,18 @@ public class UpdateChecker{
logger.warn("=======================================================================");
logger.warn("You are running an outdated version of AdvancedServerList!");
logger.warn("");
logger.warn("Your version: %s", core.getVersion());
logger.warn("Modrinth: %s", version.versionNumber());
logger.warn("Your version: <white>%s</white>", core.getVersion());
logger.warn("Modrinth: <white>%s</white>", version.versionNumber());
logger.warn("");
if(!version.isRelease()){
logger.warn("WARNING!");
logger.warn("<bold>WARNING!</bold>");
logger.warn("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
logger.warn("");
}
logger.warn("Download the latest version from here:");
logger.warn("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
logger.warn("<white>https://modrinth.com/plugin/advancedserverlist/version/%s</white>", version.id());
logger.warn("=======================================================================");
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,172 @@
/*
* MIT License
*
* Copyright (c) 2022-2025 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.commands;
import ch.andre601.advancedserverlist.api.objects.NullBool;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class ProfileOptionsSender{
private final List<OptionStringBuilder> builders = new ArrayList<>();
private final String file;
public ProfileOptionsSender(String file){
this.file = file;
}
public ProfileOptionsSender append(OptionStringBuilder builder){
this.builders.add(builder.file(file));
return this;
}
public void send(CmdSender sender){
sender.sendMsg();
sender.sendPrefixedMsg("Profile Info [<white>%s</white>]", file);
for(OptionStringBuilder builder : builders){
sender.sendMsg(builder.build());
}
sender.sendMsg();
sender.sendMsg("[<grey>Hover for info, click for command</grey>]");
sender.sendMsg();
}
public static class OptionStringBuilder{
public static OptionStringBuilder of(String displayName, String hover){
return new OptionStringBuilder(displayName)
.hover(hover == null || hover.isEmpty() ? "<i>Not set</i>" : hover)
.color(hover == null || hover.isEmpty() ? ColorName.RED : ColorName.GREEN);
}
public static OptionStringBuilder of(String displayName, List<String> hover){
return new OptionStringBuilder(displayName)
.hover(hover == null || hover.isEmpty() ? "<i>Not set</i>" : String.join("\n<reset>", hover))
.color(hover == null || hover.isEmpty() ? ColorName.RED : ColorName.GREEN);
}
public static OptionStringBuilder of(String displayName, NullBool hover){
return new OptionStringBuilder(displayName)
.hover(hover == null || !hover.getOrDefault(false) ? "<red>Disabled</red>" : "<green>Enabled</green>")
.color(hover == null || !hover.getOrDefault(false) ? ColorName.RED : ColorName.GREEN);
}
public static OptionStringBuilder of(String displayName, int hover){
return new OptionStringBuilder(displayName)
.hover(String.valueOf(hover));
}
public static OptionStringBuilder of(String displayName){
return new OptionStringBuilder(displayName).hover(null);
}
private final String displayName;
private String file = null;
private String prefix = "├─";
private ColorName color = ColorName.AQUA;
private String hover = "<i>Not set</i>";
private String option = null;
private OptionStringBuilder(String displayName){
this.displayName = displayName;
}
public OptionStringBuilder file(String file){
this.file = file;
return this;
}
public OptionStringBuilder prefix(String prefix){
this.prefix = prefix;
return this;
}
public OptionStringBuilder color(ColorName color){
this.color = color;
return this;
}
public OptionStringBuilder hover(String hover){
this.hover = hover;
return this;
}
public OptionStringBuilder option(String option){
this.option = option;
return this;
}
public String build(){
StringBuilder builder = new StringBuilder("<grey>")
.append(prefix)
.append(" <white>[")
.append('<')
.append(color)
.append('>');
if(hover != null && !hover.isEmpty()){
builder.append("<hover:show_text:\"")
.append(hover)
.append("\">");
}
if(option != null && !option.isEmpty() && file != null && !file.isEmpty()){
builder.append("<click:suggest_command:/asl profiles set ")
.append(file)
.append(" ")
.append(option)
.append(" >");
}
builder.append(displayName);
if(option != null && !option.isEmpty())
builder.append("</click>");
if(hover != null && !hover.isEmpty())
builder.append("</hover>");
builder.append("</")
.append(color)
.append(">]</white></grey>");
return builder.toString();
}
}
enum ColorName{
RED,
GREEN,
AQUA;
@Override
public String toString(){
return this.name().toLowerCase(Locale.ROOT);
}
}
}
@@ -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();
}
@@ -25,28 +25,37 @@
package ch.andre601.advancedserverlist.core.compat.papi;
import ch.andre601.advancedserverlist.core.objects.CacheUtil;
import ch.andre601.advancedserverlist.core.objects.ValueCache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import net.william278.papiproxybridge.api.PlaceholderAPI;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
public class PAPIUtil{
private static PAPIUtil instance;
private final ValueCache<CompletableFuture<Set<String>>> serversCache = new ValueCache<>(Duration.ofSeconds(10));
private final Cache<UUID, CompletableFuture<String>> textCache = CacheBuilder.newBuilder()
.expireAfterWrite(Duration.ofSeconds(10))
.build();
private final PlaceholderAPI papi;
private final CacheUtil<String> cache = new CacheUtil<>(Duration.ofSeconds(5));
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(){
@@ -59,24 +68,11 @@ public class PAPIUtil{
}
public String getServer(){
return cache.get(() -> {
List<String> servers;
try{
Set<String> value = papi.getServers().getNow(null);
if(value == null)
return null;
servers = List.copyOf(value);
}catch(CancellationException | CompletionException ex){
return null;
}
if(servers == null || servers.isEmpty())
return null;
return servers.get(0);
});
Set<String> values = serversCache.get(papi::getServers).getNow(Collections.emptySet());
if(values.isEmpty())
return null;
return List.copyOf(values).get(0);
}
public <P> P getPlayer(Collection<P> players){
@@ -88,9 +84,8 @@ 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);
}catch(IllegalArgumentException | CancellationException | CompletionException ex){
return textCache.get(player, () -> papi.formatPlaceholders(text, carrier, player)).getNow(text);
}catch(ExecutionException 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;
@@ -38,12 +36,13 @@ import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import java.util.List;
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,61 +74,98 @@ 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("', '", entry.motd()));
event.setMotd(
ComponentParser.list(entry.motd())
List<Component> motd = entry.motd().stream()
.map(line -> ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.modifyText(text -> plugin.getCore().getTextCenterUtil().getCenteredText(text))
.toComponent()
);
)
.toList();
event.setMotd(Component.join(JoinConfiguration.separator(Component.newline()), motd));
}
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
if(hidePlayers && ignoreMaintenance(event, "hidePlayers")){
logger.debug(PingEventHandler.class, "Hide Players enabled. Hiding player count...");
if(hidePlayers && ignoreMaintenance(event, "hidePlayers") && ignoreMaintenance(event, "hidePlayersHover")){
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())
@@ -139,18 +175,27 @@ 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()));
boolean hidePlayersHover = ProfileManager.checkOption(entry.hidePlayersHoverEnabled());
if(hidePlayersHover){
logger.debug(PingEventHandler.class, "'playerCount -> hidePlayersHover' option set. Hiding Player Hover...");
event.setPlayersHidden();
}
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && !hidePlayersHover && ignoreMaintenance(event, "playerCountHover")){
logger.debug(PingEventHandler.class, "'playerCount -> hover' option set. Applying ['%s']...", String.join("', '", 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);
String faviconString = StringReplacer.modifier(entry.favicon())
.modify(text -> StringReplacer.replace(text, player, server))
.modify(text -> event.parsePAPIPlaceholders(text, player))
.asString();
F favicon = plugin.getFaviconHandler().getFavicon(faviconString);
F favicon = plugin.getFaviconHandler().favicon(faviconString);
if(favicon == null){
logger.debugWarn(PingEventHandler.class, "Favicon was invalid or not yet resolved! Using default favicon of Server/Proxy...");
@@ -169,20 +214,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,57 @@ public class ConfigMigrator{
public static ConfigurationTransformation.Versioned create(){
return ConfigurationTransformation.versionedBuilder()
.versionKey("configVersion")
.addVersion(LATEST, fourToFive())
.addVersion(LATEST, eightToNine())
.addVersion(8, sevenToEight())
.addVersion(7, sixToSeven())
.addVersion(6, fiveToSix())
.addVersion(5, fourToFive())
.addVersion(4, threeToFour())
.addVersion(3, twoToThree())
.addVersion(2, oneToTwo())
.build();
}
public static ConfigurationTransformation eightToNine(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path(), (path, value) -> {
value.node("faviconStrategy").set("resize");
return null;
})
.build();
}
public static ConfigurationTransformation sevenToEight(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path("disableDuringMaintenance"), (path, value) -> {
value.node("hidePlayersHover").set(true);
return null;
})
.build();
}
public static ConfigurationTransformation sixToSeven(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path(), (path, value) -> {
value.node("printBanner").set(true);
return null;
})
.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) -> {
@@ -111,7 +155,7 @@ public class ConfigMigrator{
versioned.apply(node);
final int endVersion = versioned.version(node);
if(startVersion < endVersion)
logger.info("Migrated config.yml from v" + startVersion + " to v" + endVersion);
logger.success("Successfully migrated config from <white>v%d</white> to <white>v%d</white>", startVersion, endVersion);
}
return node;
@@ -72,7 +72,6 @@ public class FileHandler{
}
public boolean loadConfig(){
logger.info("Loading config.yml...");
File folder = plugin.getPlugin().getFolderPath().toFile();
if(!folder.exists() && !folder.mkdirs()){
logger.warn("Couldn't create folder for plugin. Is it missing Write permissions?");
@@ -87,7 +86,7 @@ public class FileHandler{
}
Files.copy(stream, config);
logger.info("Created new config.yml!");
logger.success("Created new config.yml!");
}catch(IOException ex){
logger.warn("Cannot create config.yml for plugin.", ex);
return false;
@@ -98,24 +97,37 @@ public class FileHandler{
}
public boolean loadProfiles(){
logger.info("Loading profiles...");
if(!profilesFolder.toFile().exists() && 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;
}
logger.info("[-] Loading profiles...");
if(createFile("default.yml")){
return reloadProfiles();
}else{
return false;
}
}
public boolean createFile(String name){
if(Files.notExists(profilesFolder) && profilesFolder.toFile().mkdirs()){
logger.debugSuccess(FileHandler.class, "Successfully created profiles folder.");
}
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 <white>%s</white>", ex, name);
return false;
}
}
public boolean migrateConfig(){
@@ -147,7 +159,7 @@ public class FileHandler{
File[] files = profilesFolder.toFile().listFiles(((dir, name) -> name.endsWith(".yml")));
if(files == null || files.length == 0){
logger.warn("Cannot load files from profiles folder! No valid YAML files present.");
logger.failure("Cannot load files from profiles folder! No valid YAML files present.");
return false;
}
@@ -157,11 +169,11 @@ public class FileHandler{
continue;
profiles.add(ServerListProfile.Builder.resolve(file.getName(), tmp, logger).build());
logger.info("Loaded '%s'!", file.getName());
logger.debugSuccess(FileHandler.class, "Loaded '<white>%s</white>'!", file.getName());
}
if(profiles.isEmpty()){
logger.warn("Couldn't load any profile from profiles folder!");
logger.failure("Couldn't load any profile from profiles folder!");
return false;
}
@@ -178,7 +190,7 @@ public class FileHandler{
try{
return loader.load();
}catch(IOException ex){
logger.warn("Cannot load '%s' due to an IOException!", ex, path.toFile().getName());
logger.warn("Cannot load '<white>%s</white>' due to an IOException!", ex, path.toFile().getName());
return null;
}
}
@@ -205,11 +217,11 @@ public class FileHandler{
}
private boolean makeBackup(){
logger.info("Making backup of old config.yml...");
logger.info("[-] Making backup of old config.yml...");
File backups = plugin.getPlugin().getFolderPath().resolve("backups").toFile();
if(!backups.exists() && !backups.mkdirs()){
logger.warn("Cannot create backups folder for migration!");
logger.failure("Cannot create backups folder for migration!");
return false;
}
@@ -218,16 +230,16 @@ public class FileHandler{
File configBackup = new File(backups, "config_" + date.replace(":", "_") + ".yml");
try{
if(!configBackup.exists() && !configBackup.createNewFile()){
logger.warn("Cannot create backup file for config.yml!");
logger.failure("Cannot create backup file for config.yml!");
return false;
}
Files.copy(config, configBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
logger.info("Saved backup as '%s'!", configBackup.getName());
logger.success("Saved backup as '<white>%s</white>'!", configBackup.getName());
return true;
}catch(IOException ex){
logger.warn("Encountered IOException while trying to create a backup.", ex);
logger.failure("Encountered IOException while trying to create a backup.", ex);
return false;
}
}
@@ -27,10 +27,18 @@ package ch.andre601.advancedserverlist.core.interfaces;
public interface PluginLogger{
default void debugSuccess(Class<?> clazz, String msg, Object... args){
debug(clazz, "[<green>✓</green>] " + msg, args);
}
void debug(Class<?> clazz, String msg, Object... args);
void debugWarn(Class<?> clazz, String msg, Object... args);
default void success(String msg, Object... args){
info("[<green>✓</green>] " + msg, args);
}
void info(String msg, Object... args);
void warn(String msg, Object... args);
@@ -38,4 +46,8 @@ public interface PluginLogger{
void warn(String msg, Throwable throwable);
void warn(String msg, Throwable throwable, Object... args);
default void failure(String msg, Object... args){
warn("[<red>x</red>] " + msg, args);
}
}
@@ -25,12 +25,12 @@
package ch.andre601.advancedserverlist.core.interfaces.commands;
import net.kyori.adventure.audience.Audience;
public interface CmdSender{
String prefix = "<grey>[<gradient:aqua:white>AdvancedServerList</gradient>] ";
String errorPrefix = "<grey>[<gradient:dark_red:red>AdvancedServerList</gradient>] ";
boolean hasPermission(String permission);
String prefix = "<grey>[<aqua>ASL</aqua>] ";
String errorPrefix = "<grey>[<red>ASL</red>] ";
void sendMsg(String msg, Object... args);
@@ -45,4 +45,8 @@ public interface CmdSender{
default void sendErrorMsg(String msg, Object... args){
sendMsg(errorPrefix + msg, args);
}
Audience audience();
boolean isPlayer();
}
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
* Copyright (c) 2022-2025 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
@@ -20,24 +20,15 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.velocity.commands;
package ch.andre601.advancedserverlist.core.interfaces.commands;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import com.velocitypowered.api.command.SimpleCommand;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.SenderMapper;
public class CmdAdvancedServerList implements SimpleCommand{
public interface CommandManagerInterface<S>{
CommandManager<CmdSender> commandHandler();
private final VelocityCore plugin;
public CmdAdvancedServerList(VelocityCore plugin){
this.plugin = plugin;
}
@Override
public void execute(Invocation invocation){
plugin.getCore().getCommandHandler().handle(new VelocityCmdSender(invocation.source()), invocation.arguments());
}
SenderMapper<S, CmdSender> senderMapper();
}
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
* Copyright (c) 2022-2025 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
@@ -20,28 +20,22 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.interfaces.commands;
import java.util.Locale;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public abstract class PluginCommand{
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CommandType{
Type value();
private final String argument;
public PluginCommand(String argument){
this.argument = argument;
enum Type{
ALL,
PLAYER_ONLY
}
public String getArgument(){
return argument;
}
public String getPermission(){
return "advancedserverlist.command." + getArgument().toLowerCase(Locale.ROOT);
}
public abstract void handle(CmdSender sender, String[] args);
}
@@ -27,15 +27,15 @@ 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.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import org.incendo.cloud.CommandManager;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
public interface PluginCore<F>{
void loadCommands();
void loadEvents();
void loadMetrics();
@@ -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,9 @@ public interface PluginCore<F>{
FaviconHandler<F> getFaviconHandler();
String getPlatformName();
CommandManager<CmdSender> getCommandManager();
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();
@@ -50,6 +52,8 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
void setPlayers(List<String> players, P player, GenericServer server);
void setPlayersHidden();
void setFavicon(F favicon);
void setDefaultFavicon();
@@ -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("[<white>Migrator - MiniMOTD</white>] Cannot find a main.conf file in <white>/plugins/%s/</white> 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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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()){
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()){
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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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("[<white>Migrator - MiniMOTD</white>] 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());
}
}
}
@@ -59,26 +59,55 @@ public class SLPConfigMigrator{
"(?<end>#[a-fA-F0-9]{6})" + // Ending color
"%" +
"(?<text>.+?)" + // Text
"%gradient%");
"%gradient%"
);
private static final Map<String, String> STATIC_REPLACEMENTS = Map.of(
"%player%", "${player name}",
"%uuid%", "${player uuid}",
"%_uuid_%", "${player uuid}",
"%online%", "${server playersOnline}",
"%max%", "${server playersMax}");
"%max%", "${server playersMax}"
);
private static final Map<String, String> COLOR_TO_MINIMESSAGE_TAG = new HashMap<>(){{
// Color Codes.
put("a", "<green>");
put("b", "<aqua>");
put("c", "<red>");
put("d", "<light_purple>");
put("e", "<yellow>");
put("f", "<white>");
put("0", "<black>");
put("1", "<dark_blue>");
put("2", "<dark_green>");
put("3", "<dark_aqua>");
put("4", "<dark_red>");
put("5", "<dark_purple>");
put("6", "<gold>");
put("7", "<grey>");
put("8", "<dark_grey>");
put("9", "<blue>");
// Formatting Codes
put("k", "<obfuscated>");
put("l", "<bold>");
put("m", "<strikethrough>");
put("n", "<underlined>");
put("o", "<italic>");
put("r", "<reset>");
}};
public static int migrate(AdvancedServerList<?> core, CmdSender sender){
ServerListPlusCore slpCore = ServerListPlusCore.getInstance();
PluginLogger logger = core.getPlugin().getPluginLogger();
if(slpCore == null){
logger.warn("[Migrator - ServerListPlus] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
return 0;
}
ServerStatusConf conf = slpCore.getConf(ServerStatusConf.class);
if(conf == null){
logger.warn("[Migrator - ServerListPlus] Cannot migrate ServerListPlus configuration. Received configuration was null.");
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus configuration. Received configuration was null.");
return 0;
}
@@ -101,7 +130,7 @@ public class SLPConfigMigrator{
private static int parseConf(AdvancedServerList<?> core, CmdSender sender, PersonalizedStatusConf.StatusConf conf, Type type){
PluginLogger logger = core.getPlugin().getPluginLogger();
if(conf == null){
logger.info("[Migrator - ServerListPlus] No StatusConf found for type %s. Skipping...", type.getName());
logger.info("[<white>Migrator - ServerListPlus</white>] No StatusConf found for type <white>%s</white>. Skipping...", type.getName());
sender.sendPrefixedMsg(" -> Not found! Skipping...");
return 0;
@@ -129,7 +158,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,8 +168,9 @@ public class SLPConfigMigrator{
.map(ProfileEntry.Builder::build)
.toList();
if(entry.isInvalid() && profileEntries.isEmpty()){
logger.warn("[Migrator - ServerListPlus] Unable to parse ServerListPlus configuration of type %s. Generated ProfileEntry was invalid.", type.getName());
boolean profilesInvalid = profileEntries.isEmpty() || profileEntries.stream().anyMatch(ProfileEntry::isInvalid);
if(entry.isInvalid() && profilesInvalid){
logger.warn("[<white>Migrator - ServerListPlus</white>] Unable to parse ServerListPlus configuration of type <white>%s</white>. Generated ProfileEntry was invalid.", type.getName());
sender.sendErrorMsg(" -> <red>Received invalid Configuration.");
return 0;
@@ -148,7 +178,7 @@ public class SLPConfigMigrator{
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve(type.getFile());
if(Files.exists(profile)){
logger.warn("[Migrator - ServerListPlus] Cannot create new file %s. One with the same name is already present", type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot create new file <white>%s</white>. One with the same name is already present", type.getFile());
sender.sendErrorMsg(" -> <red>File</red> %s <red>already present.", type.getFile());
return 0;
@@ -157,7 +187,7 @@ public class SLPConfigMigrator{
try{
Files.createFile(profile);
}catch(IOException ex){
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to create file %s.", ex, type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to create file <white>%s</white>.", ex, type.getFile());
sender.sendErrorMsg(" -> <red>File creation error.");
return 0;
@@ -174,14 +204,14 @@ public class SLPConfigMigrator{
try{
node = loader.load();
}catch(IOException ex){
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to load file %s.", ex, type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to load file <white>%s</white>.", ex, type.getFile());
sender.sendErrorMsg(" -> <red>File loading error.");
return 0;
}
if(node == null){
logger.warn("[Migrator - ServerListPlus] Cannot migrate Configuration of type %s. ConfigurationNode was null.", type.getName());
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate Configuration of type <white>%s</white>. ConfigurationNode was null.", type.getName());
sender.sendErrorMsg(" -> <red>File loading error.");
return 0;
@@ -193,9 +223,7 @@ public class SLPConfigMigrator{
if(type == Type.PERSONALIZED){
node.node("condition")
.set("${player name} != \"" +
core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") +
"\"");
.set("${player name} != \"" + core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") + "\"");
}else
if(type == Type.BANNED){
node.node("condition")
@@ -208,7 +236,7 @@ public class SLPConfigMigrator{
node.set(entry);
}catch(SerializationException ex){
logger.warn("Encountered a SerializationException while setting values.", ex);
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered a SerializationException while setting values.", ex);
sender.sendErrorMsg(" -> <red>Error while updating file</red> %s<red>.", type.getFile());
return 0;
@@ -220,7 +248,7 @@ public class SLPConfigMigrator{
return 1;
}catch(IOException ex){
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to save new file %s.", ex, type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to save new file <white>%s</white>.", ex, type.getFile());
sender.sendErrorMsg(" -> <red>File saving error.");
return 0;
@@ -371,32 +399,11 @@ public class SLPConfigMigrator{
if(colorCodeMatcher.find()){
builder.setLength(0);
do{
String color = colorCodeMatcher.group("color").toLowerCase(Locale.ROOT);
switch(color){
case "a" -> colorCodeMatcher.appendReplacement(builder, "<green>");
case "b" -> colorCodeMatcher.appendReplacement(builder, "<aqua>");
case "c" -> colorCodeMatcher.appendReplacement(builder, "<red>");
case "d" -> colorCodeMatcher.appendReplacement(builder, "<light_purple>");
case "e" -> colorCodeMatcher.appendReplacement(builder, "<yellow>");
case "f" -> colorCodeMatcher.appendReplacement(builder, "<white>");
case "k" -> colorCodeMatcher.appendReplacement(builder, "<obfuscated>");
case "l" -> colorCodeMatcher.appendReplacement(builder, "<bold>");
case "m" -> colorCodeMatcher.appendReplacement(builder, "<strikethrough>");
case "n" -> colorCodeMatcher.appendReplacement(builder, "<underlined>");
case "o" -> colorCodeMatcher.appendReplacement(builder, "<italic>");
case "r" -> colorCodeMatcher.appendReplacement(builder, "<reset>");
case "0" -> colorCodeMatcher.appendReplacement(builder, "<black>");
case "1" -> colorCodeMatcher.appendReplacement(builder, "<dark_blue>");
case "2" -> colorCodeMatcher.appendReplacement(builder, "<dark_green>");
case "3" -> colorCodeMatcher.appendReplacement(builder, "<dark_aqua>");
case "4" -> colorCodeMatcher.appendReplacement(builder, "<dark_red>");
case "5" -> colorCodeMatcher.appendReplacement(builder, "<dark_purple>");
case "6" -> colorCodeMatcher.appendReplacement(builder, "<gold>");
case "7" -> colorCodeMatcher.appendReplacement(builder, "<grey>");
case "8" -> colorCodeMatcher.appendReplacement(builder, "<dark_grey>");
case "9" -> colorCodeMatcher.appendReplacement(builder, "<blue>");
// This one shouldn't be reachable given the pattern, but you never know...
default -> colorCodeMatcher.appendReplacement(builder, "&" + color);
for(Map.Entry<String, String> colorCodes : COLOR_TO_MINIMESSAGE_TAG.entrySet()){
if(!colorCodeMatcher.group("color").equalsIgnoreCase(colorCodes.getKey()))
continue;
colorCodeMatcher.appendReplacement(builder, colorCodes.getValue());
}
}while(colorCodeMatcher.find());
@@ -28,12 +28,12 @@ package ch.andre601.advancedserverlist.core.objects;
import java.time.Duration;
import java.util.function.Supplier;
public class CacheUtil<T>{
public class ValueCache<T>{
private final Duration duration;
private CacheValue<T> cache = null;
public CacheUtil(Duration duration){
public ValueCache(Duration duration){
this.duration = duration;
}
@@ -29,7 +29,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.List;
import java.util.function.Function;
public class ComponentParser{
@@ -52,12 +51,13 @@ public class ComponentParser{
return new ComponentParser(text);
}
public static ComponentParser list(List<String> lines){
return new ComponentParser(String.join("\n", lines));
public static ComponentParser textFormatted(String text, Object... args){
return text(String.format(text, args));
}
public ComponentParser modifyText(Function<String, String> function){
this.text = function.apply(text);
return this;
}
@@ -65,8 +65,16 @@ 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());
}
public String toStringStriped(){
return mm.stripTags(text);
}
}
@@ -0,0 +1,136 @@
package ch.andre601.advancedserverlist.core.parsing;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.kyori.adventure.text.flattener.ComponentFlattener;
import net.kyori.adventure.text.flattener.FlattenerListener;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class TextCenterUtil{
private final ComponentFlattener COMPONENT_FLATTENER = ComponentFlattener.textOnly();
private final double MAX_WIDTH = 270.0; // Max width of the MOTD
private final int SPACE_WIDTH = 4;
private final Map<String, FontInfo> charWidths;
public TextCenterUtil(AdvancedServerList<?> plugin){
charWidths = loadFontWidths(plugin);
}
public String getCenteredText(String text){
if(!text.toLowerCase(Locale.ROOT).startsWith("<center>"))
return text;
if(getDefault() == null)
return text;
text = text.substring("<center>".length());
TextFlattenerListener listener = new TextFlattenerListener(this);
COMPONENT_FLATTENER.flatten(ComponentParser.text(text).toComponent(), listener);
double width = listener.getWidth();
if(width >= MAX_WIDTH)
return text;
return createSpaces(width) + text;
}
private double getCharWidth(int codePoint, boolean isBold, String fontName){
FontInfo font = charWidths.getOrDefault(fontName, getDefault());
if(font == null)
return -1.0;
int index = Arrays.binarySearch(font.codePoints, codePoint);
if(index < 0){
return isBold ? 7.0 : 6.0;
}else{
return isBold ? font.advanceBf[index] : font.advance[index];
}
}
private FontInfo getDefault(){
return charWidths.get("minecraft:default");
}
private String createSpaces(double length){
double remainder = MAX_WIDTH - length;
int padding = (int)Math.max(0, Math.floor(remainder / 2.0) - 1);
return " ".repeat(Math.floorDiv(padding, SPACE_WIDTH));
}
private Map<String, FontInfo> loadFontWidths(AdvancedServerList<?> plugin){
try(InputStream stream = plugin.getClass().getResourceAsStream("/char-widths.json.gz")){
if(stream == null){
plugin.getPlugin().getPluginLogger().warn("Internal char-widths.json.gz couldn't be retrieved.");
plugin.getPlugin().getPluginLogger().warn("The <center> Placeholder won't work.");
return new HashMap<>();
}
GZIPInputStream gzipStream = new GZIPInputStream(stream);
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipStream));
return new Gson().fromJson(reader, new TypeToken<Map<String, FontInfo>>(){}.getType());
}catch(IOException ex){
plugin.getPlugin().getPluginLogger().warn("Encountered IOException while loading font widths.");
plugin.getPlugin().getPluginLogger().warn("The <center> Placeholder won't work.");
plugin.getPlugin().getPluginLogger().warn("Cause: <white>%s</white>", ex.getMessage());
return new HashMap<>();
}
}
private static class TextFlattenerListener implements FlattenerListener{
private double width = 0.0;
private boolean isBold = false;
private String font = "minecraft:default";
private final TextCenterUtil instance;
public TextFlattenerListener(TextCenterUtil instance){
this.instance = instance;
}
@Override
public void pushStyle(@NotNull Style style){
if(style.hasDecoration(TextDecoration.BOLD))
isBold = true;
if(style.font() != null)
font = style.font().asString();
}
@Override
public void component(@NotNull String text){
for(int i = 0; i < text.length(); i++){
width += instance.getCharWidth(text.codePointAt(i), isBold, font);
}
}
@Override
public void popStyle(@NotNull Style style){
if(style.hasDecoration(TextDecoration.BOLD))
isBold = false;
}
public double getWidth(){
return width;
}
}
private record FontInfo(int[] codePoints, float[] advance, float[] advanceBf){}
}
@@ -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,23 +41,23 @@ 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);
logger.warn("Encountered <white>%d</white> Error(s) while parsing condition for file '<white>%s</white>':", collector.getWarnings().size(), file);
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(" -> %s", context.message());
logger.warn(" - At position <white>%s</white>:", context.position() == -1 ? "<italic>Unknown</italic>" : context.position());
logger.warn(" <white>%s</white>", condition);
logger.warn(" ".repeat(context.position() + 3) + "<red>^</red>");
logger.warn(" <grey>-></grey> %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()
@@ -153,7 +146,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
try{
this.profiles = node.node("profiles").getList(ProfileEntry.class);
}catch(SerializationException ex){
logger.warn("Encountered a SerializationException while resolving the profiles entry for %s", ex, fileName);
logger.warn("Encountered a SerializationException while resolving the profiles entry for <white>%s</white>", ex, fileName);
}
return this;
@@ -166,7 +159,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
try{
this.defaultProfile = node.get(ProfileEntry.class);
}catch(SerializationException ex){
logger.warn("Encountered a SerializationException while resolving the global profile for %s", ex, fileName);
logger.warn("Encountered a SerializationException while resolving the global profile for <white>%s</white>", ex, fileName);
}
return this;
}
@@ -76,7 +76,14 @@ public class CustomExpressionTokenizer{
}
}
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
if(position.getIndex() >= text.length()){
collector.appendWarningFormatted(
"Current index position (%d) is larger or equal to Text length (%d) for condition '%s'",
position.getIndex(), text.length(), text
);
}else{
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
}
break;
}
@@ -1,201 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.profiles.favicon;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Stream;
public class FaviconHandler<F>{
private final AdvancedServerList<F> core;
private final PluginLogger logger;
private final ThreadPoolExecutor faviconThreadPool;
private final Cache<String, CompletableFuture<F>> faviconCache;
private final Map<String, F> localFavicons = new HashMap<>();
private final HttpClient client = HttpClient.newHttpClient();
public FaviconHandler(AdvancedServerList<F> core){
this.core = core;
this.logger = core.getPlugin().getPluginLogger();
this.faviconThreadPool = createFaviconThreadPool();
this.faviconCache = CacheBuilder.newBuilder()
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
.build();
loadLocalFavicons();
}
public F getFavicon(String input){
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
}
try{
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
}catch(ExecutionException ex){
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
return null;
}
}
public void cleanCache(){
faviconCache.invalidateAll();
loadLocalFavicons();
}
private CompletableFuture<F> getFuture(String input){
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
logger.debug(FaviconHandler.class, "Resolving URL '%s'...", input);
return CompletableFuture.supplyAsync(() -> fromURL(core, input), this.faviconThreadPool);
}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]));
}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);
}
}
private void loadLocalFavicons(){
this.localFavicons.clear();
logger.info("Loading local image files as Favicons...");
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
if(!Files.exists(folder)){
try{
Files.createDirectories(folder);
logger.info("Created favicons folder.");
}catch(IOException ex){
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
return;
}
}
try(Stream<Path> pathStream = Files.list(folder)){
pathStream.filter(Files::isRegularFile)
.filter(file -> file.getFileName().toString().endsWith(".png"))
.forEach(this::loadFile);
}catch(IOException ex){
logger.warn("Cannot load files from Favicons folder.", ex);
}
}
private void loadFile(Path path){
try(InputStream stream = Files.newInputStream(path)){
F favicon = createFavicon(stream);
if(favicon == null){
logger.warn("Cannot create Favicon from file '%s'. Received Favicon was null.", path.getFileName().toString());
return;
}
localFavicons.put(path.getFileName().toString().split("\\.")[0], 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);
}
}
private F fromURL(AdvancedServerList<F> core, String url){
try{
logger.debug(FaviconHandler.class, "Creating Request for URL '%s'...", url);
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
.build();
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
return createFavicon(stream);
}catch(InterruptedException | IOException ex){
logger.warn("Cannot create Favicon from URL '%s'. Encountered an Exception.", ex, url);
return null;
}
}catch(URISyntaxException ex){
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
return null;
}
}
private F createFavicon(InputStream stream){
try{
logger.debug(FaviconHandler.class, "Creating BufferedImage from InputStream...");
BufferedImage original = ImageIO.read(stream);
if(original == null){
logger.warn("Cannot create Favicon. Received null BufferedImage.");
return null;
}
// Don't waste resources resizing images already having right size.
if(original.getWidth() == 64 && original.getHeight() == 64){
logger.debug(FaviconHandler.class, "BufferedImage is 64x64 pixels. No resizing needed.");
return core.getPlugin().createFavicon(original);
}
logger.debug(FaviconHandler.class, "Resizing image to 64x64 pixels...");
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = image.createGraphics();
graphics2D.drawImage(original, 0, 0, 64, 64, null);
graphics2D.dispose();
logger.debug(FaviconHandler.class, "Image resized! Returning Favicon...");
return core.getPlugin().createFavicon(image);
}catch(Exception ex){
logger.warn("Unable to create Favicon. Received Exception.", ex);
return null;
}
}
private ThreadPoolExecutor createFaviconThreadPool(){
return new ThreadPoolExecutor(3, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1024), r -> {
Thread t = new Thread(r, "AdvancedServerList-FaviconThread");
t.setDaemon(true);
return t;
});
}
}
@@ -0,0 +1,336 @@
package ch.andre601.advancedserverlist.core.profiles.handlers;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class FaviconHandler<F>{
private final AdvancedServerList<F> core;
private final PluginLogger logger;
private final ThreadPoolExecutor faviconThreadPool;
private final Cache<String, CompletableFuture<F>> faviconCache;
private final Random random = new Random();
private final HttpClient client = HttpClient.newHttpClient();
private final Map<String, FaviconPair<F>> localFavicons = new HashMap<>();
public FaviconHandler(AdvancedServerList<F> core){
this.core = core;
this.logger = core.getPlugin().getPluginLogger();
this.faviconThreadPool = createThreadPool();
this.faviconCache = CacheBuilder.newBuilder()
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
.build();
loadLocalFavicons();
}
public F favicon(String input){
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT))){
logger.debug(FaviconHandler.class, "Returning local Favicon '%s'.", input);
return localFavicons.get(input.toLowerCase(Locale.ROOT)).favicon();
}
if(input.equalsIgnoreCase("random")){
logger.debug(FaviconHandler.class, "Returning random local Favicon.");
FaviconPair<F> pair = randomFavicon();
if(pair == null){
logger.warn("Cannot return random Favicon. Make sure PNGs are available in the Favicons folder!");
return null;
}
return pair.favicon();
}
CompletableFuture<F> favicon = faviconCache.getIfPresent(input);
if(favicon != null)
return favicon.getNow(null);
logger.debug(FaviconHandler.class, "Processing '%s'", input);
if(input.contains(";")){
String[] parts = input.split(";");
logger.debug(FaviconHandler.class, "Handling multi-part Favicon: ['%s']", String.join("', '", parts));
favicon = CompletableFuture.supplyAsync(() -> {
List<BufferedImage> images = new ArrayList<>();
Arrays.stream(parts).forEach(part -> {
logger.debug(FaviconHandler.class, "Creating BufferedImage for part '%s'...", part);
images.add(create(part));
});
if(images.isEmpty()){
logger.debugWarn(FaviconHandler.class, "Unable to create Multi-part Favicon. List was empty.");
return null;
}
return composeFavicon(images);
}, faviconThreadPool);
}else{
logger.debug(FaviconHandler.class, "Handling Favicon input '%s'...", input);
favicon = CompletableFuture.supplyAsync(() -> {
logger.debug(FaviconHandler.class, "Creating BufferedImage for '%s'...", input);
BufferedImage image = create(input);
if(image == null){
logger.warn("Cannot create Favicon for '%s'. BufferedImage was null!", input);
return null;
}
return createFavicon(image);
}, faviconThreadPool);
}
faviconCache.put(input, favicon);
return favicon.getNow(null);
}
public void cleanCache(){
localFavicons.clear();
loadLocalFavicons();
}
private F composeFavicon(List<BufferedImage> images){
logger.debug(FaviconHandler.class, "Composing Favicon out of %d part(s)...", images.size());
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
String strategy = core.getFileHandler().getString("resize", "faviconStrategy");
int layer = 0;
for(BufferedImage img : images){
layer++;
logger.debug(FaviconHandler.class, "Applying layer %d...", layer);
if(img == null){
logger.debugWarn(FaviconHandler.class, "Layer %d was null! Skipping...", layer);
continue;
}
switch(strategy.toLowerCase(Locale.ROOT)){
case "center" -> {
int height = img.getHeight();
int width = img.getWidth();
int posHeight = 0;
int posWidth = 0;
if(height != 64){
posHeight = (64 - height) / 2;
}
// 64 - 128 = -64
if(width != 64){
posWidth = (64 - width) / 2;
}
graphics.drawImage(img, posWidth, posHeight, img.getWidth(), img.getHeight(), null);
}
case "none" -> graphics.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
default -> graphics.drawImage(img, 0, 0, 64, 64, null);
}
logger.debug(FaviconHandler.class, "Applied layer %d!", layer);
}
graphics.dispose();
logger.debug(FaviconHandler.class, "Image Composing complete! Creating Favicon instance...");
return createFavicon(image);
}
private BufferedImage create(String input){
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
logger.debug(FaviconHandler.class, "Handling URL '%s'...", input);
return fromURL(input);
}else
if(input.equalsIgnoreCase("random")){
logger.debug(FaviconHandler.class, "Returning random local Favicon...");
FaviconPair<F> pair = randomFavicon();
return pair == null ? null : pair.image();
}else
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
logger.debug(FaviconHandler.class, "Returning local Favicon '%s'...", input);
return localFavicons.get(input.toLowerCase(Locale.ROOT)).image();
}else{
logger.debug(FaviconHandler.class, "Handling Player Name/UUID '%s'...", input);
return fromURL("https://mc-heads.net/avatar/" + input + "/64");
}
}
private FaviconPair<F> randomFavicon(){
if(localFavicons.isEmpty())
return null;
List<FaviconPair<F>> favicons = new ArrayList<>(localFavicons.values());
if(favicons.isEmpty())
return null;
if(favicons.size() == 1)
return favicons.getFirst();
synchronized(random){
return favicons.get(random.nextInt(favicons.size()));
}
}
private void loadLocalFavicons(){
this.localFavicons.clear();
logger.info("[-] Loading local images as Favicons...");
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
if(!Files.exists(folder)){
try{
Files.createDirectories(folder);
logger.debugSuccess(FaviconHandler.class, "Created favicons folder");
}catch(IOException ex){
logger.warn("Encountered IOException while creating favicons folder.", ex);
return;
}
}
try(Stream<Path> stream = Files.list(folder)){
stream.filter(Files::isRegularFile)
.filter(file -> file.getFileName().toString().endsWith(".png"))
.forEach(this::loadFile);
logger.success("Loaded <white>%s</white> local Favicon(s).", localFavicons.size());
}catch(IOException ex){
logger.warn("Encountered IOException while loading local favicons.", ex);
}
}
private void loadFile(Path path){
try(InputStream stream = Files.newInputStream(path)){
BufferedImage image = createBufferedImage(stream);
if(image == null)
return;
F favicon = core.getPlugin().createFavicon(image);
if(favicon == null)
return;
localFavicons.put(path.getFileName().toString().toLowerCase(Locale.ROOT), new FaviconPair<>(image, favicon));
}catch(IOException ex){
logger.warn("Encountered IOException while creating a Favicon from '%s'.", ex, path.getFileName().toString());
}catch(Exception ex){
logger.warn("Encountered an Exceotion while creating a Favicon from '%s'.", ex, path.getFileName().toString());
}
}
private BufferedImage fromURL(String url){
try{
logger.debug(FaviconHandler.class, "Creating request for URL '%s'...", url);
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
.build();
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
return createBufferedImage(stream);
}catch(IOException ex){
logger.warn("Encountered IOException while performing a web request for '%s'.", ex, url);
return null;
}catch(InterruptedException ex){
logger.warn("Encountered an InterruptedException while performing a web request for '%s'.", ex, url);
return null;
}
}catch(URISyntaxException ex){
logger.warn("Received URISyntaxException for URL '%s'", ex, url);
return null;
}
}
private BufferedImage createBufferedImage(InputStream stream){
logger.debug(FaviconHandler.class, "Creating BufferedImage from InputStream...");
try{
BufferedImage original = ImageIO.read(stream);
if(original == null){
logger.warn("Cannot create Favicon. Received a null BufferedImage!");
return null;
}
logger.debug(FaviconHandler.class, "Check image size for possible resizing...");
if(original.getHeight() == 64 && original.getWidth() == 64){
logger.debug(FaviconHandler.class, "Image is 64x64. No resizing needed!");
return original;
}
logger.debug(FaviconHandler.class, "Applying Favicon resize strategy...");
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
String resizeMode = core.getFileHandler().getString("resize", "faviconStrategy");
switch(resizeMode.toLowerCase(Locale.ROOT)){
case "center" -> {
int height = original.getHeight();
int width = original.getWidth();
int posHeight = 0;
int posWidth = 0;
if(height != 64){
posHeight = (64 - height) / 2;
}
if(width != 64){
posWidth = (64 - width) / 2;
}
graphics.drawImage(original, posWidth, posHeight, original.getWidth(), original.getHeight(), null);
}
case "none" -> graphics.drawImage(original, 0, 0, original.getWidth(), original.getHeight(), null);
default -> graphics.drawImage(original, 0, 0, 64, 64, null);
}
graphics.dispose();
logger.debug(FaviconHandler.class, "Image resized. Returning it...");
return image;
}catch(IOException ex){
logger.warn("Encountered an IOException while processing Favicon!", ex);
return null;
}
}
private F createFavicon(BufferedImage image){
try{
return core.getPlugin().createFavicon(image);
}catch(Exception ex){
logger.warn("Encountered an Exception while trying to create a Favicon instance.", ex);
return null;
}
}
private ThreadPoolExecutor createThreadPool(){
return new ThreadPoolExecutor(3, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1024), r -> {
Thread t = new Thread(r, "AdvancedServerList-FaviconThread");
t.setDaemon(true);
return t;
});
}
private record FaviconPair<F>(BufferedImage image, F favicon){}
}
@@ -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;
}
@@ -79,43 +79,41 @@ public class PlayerHandler{
try(BufferedReader reader = Files.newBufferedReader(cache)){
cachedPlayers = gson.fromJson(reader, listType);
}catch(IOException ex){
logger.warn("Encountered IOException while reading the playercache.json file!", ex);
logger.warn("Encountered IOException while reading the <white>playercache.json</white> file!", ex);
return;
}catch(JsonIOException | JsonSyntaxException ex){
logger.warn("Encountered Json exception while parsing playercache.json file!", ex);
logger.warn("Encountered JsonSyntaxException while parsing <white>playercache.json</white> file!", ex);
return;
}
// In case Gson messes up... I guess.
if(cachedPlayers == null){
logger.warn("Couldn't load players from playercache.json file. Is the JSON valid?");
logger.warn("Couldn't load players from <white>playercache.json</white> file. Is the JSON valid?");
// Create new ArrayList instance to avoid further issues.
cachedPlayers = new ArrayList<>();
return;
}
logger.info("Loaded %d players into cache!", cachedPlayers.size());
logger.success("Loaded <white>%d</white> players into cache!", cachedPlayers.size());
}
public void save(){
if(cachedPlayers.isEmpty()){
logger.info("No players in cache to save. Skipping...");
logger.debug(PlayerHandler.class, "No players in cache to save. Skipping...");
return;
}
if(core.getFileHandler().getBoolean("disableCache")){
logger.info("'disable_cache' is set to true. Skipping saving of cached players...");
logger.debug(PlayerHandler.class, "[-] 'disable_cache' is set to true. Not saving cached players.");
return;
}
try(BufferedWriter writer = Files.newBufferedWriter(cache, StandardCharsets.UTF_8)){
gson.toJson(cachedPlayers, listType, writer);
logger.info("Successfully saved playercache.json file.");
logger.success("Successfully saved <white>playercache.json</white> file.");
}catch(IOException ex){
logger.warn("Encountered IOException while saving cached players to playercache.json!", ex);
logger.failure("Encountered IOException while saving cached players to <white>playercache.json</white>!", 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,36 @@ 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);
NullBool hidePlayersHoverEnabled = resolve(defEntry, entry, ProfileEntry::hidePlayersHoverEnabled);
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)
.hidePlayersHoverEnabled(hidePlayersHoverEnabled)
.extraPlayersCount(extraPlayersCount)
.maxPlayersCount(maxPlayersCount)
.onlinePlayersCount(onlinePlayersCount)
.build();
}
public static ServerListProfile resolveProfile(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
@@ -67,7 +82,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 +97,11 @@ 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");
NullBool hidePlayersHoverEnabled = resolveNullBool(node, "playerCount", "hidePlayersHover");
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,89 +111,29 @@ public class ProfileManager{
.hidePlayersEnabled(hidePlayers)
.extraPlayersEnabled(extraPlayersEnabled)
.maxPlayersEnabled(maxPlayersEnabled)
.onlinePlayersEnabled(onlinePlayersEnabled)
.hidePlayersHoverEnabled(hidePlayersHoverEnabled)
.extraPlayersCount(extraPlayers)
.maxPlayersCount(maxPlayers)
.onlinePlayersCount(onlinePlayers)
.build();
}
public static boolean checkOption(Object obj){
if(obj == null)
return false;
return switch(obj){
case List<?> list -> !list.isEmpty(); // Check if list isn't empty
case String str -> !str.isEmpty(); // Check if String is not empty
case NullBool nb -> nb.getOrDefault(false); // Return NullBool's value
case null, default -> false;
};
if(obj instanceof List<?> list){
return !list.isEmpty(); // Check if list isn't empty
}else
if(obj instanceof String str){
return !str.isEmpty(); // Check if String is not empty
}else
if(obj instanceof NullBool nb){
return nb.getOrDefault(false); // Return NullBool's value
}
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 +151,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();
}
}
@@ -53,9 +53,12 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
node.node("playerCount", "text").set(profile.playerCountText());
node.node("favicon").set(profile.favicon());
node.node("playerCount", "hidePlayers").set(profile.hidePlayersEnabled().getOrDefault(false));
node.node("playerCount", "hidePlayersHover").set(profile.hidePlayersHoverEnabled().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());
}
}
@@ -34,9 +34,14 @@ import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.toke
import ch.andre601.expressionparser.ParseWarnCollector;
import java.text.ParsePosition;
import java.util.function.Function;
public class StringReplacer{
public static StringModifier modifier(String text){
return new StringModifier(text);
}
public static String replace(String input, GenericPlayer player, GenericServer server){
if(input == null)
return null;
@@ -64,8 +69,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();
@@ -74,6 +77,9 @@ public class StringReplacer{
boolean identified = false;
boolean invalid = true;
int placeholderStart = position.getIndex() - 1;
int valueStart = position.getIndex() - 1;
char[] chars = input.substring(index).toCharArray();
for(final char c : chars){
index++;
@@ -85,6 +91,7 @@ public class StringReplacer{
if(c == ' ' && !identified){
identified = true;
valueStart = index + 1;
continue;
}
@@ -100,10 +107,6 @@ public class StringReplacer{
StringBuilder raw = new StringBuilder();
// Condition parsing needs one extra increase of index... for some reason
if(collector != null)
index++;
position.setIndex(index);
if(invalid){
@@ -113,7 +116,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 '<white>%s</white>' does not have a closing bracket (})", raw.toString());
return raw.toString();
}
@@ -128,7 +131,7 @@ public class StringReplacer{
raw.append('}');
if(collector != null)
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
collector.appendWarningFormatted(placeholderStart, "Placeholder '<white>%s</white>' does not have any available PlaceholderProvider", raw.toString());
return raw.toString();
}
@@ -143,11 +146,29 @@ public class StringReplacer{
raw.append('}');
if(collector != null)
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'", raw.toString(), valuesStr);
collector.appendWarningFormatted(valueStart, "Placeholder '<white>%s</white>' has an invalid value String '<white>%s</white>'", raw.toString(), valuesStr);
return raw.toString();
}
return replacement;
}
public static class StringModifier{
private String value;
public StringModifier(String value){
this.value = value;
}
public StringModifier modify(Function<String, String> function){
this.value = function.apply(value);
return this;
}
public String asString(){
return value;
}
}
}
Binary file not shown.
+34 -1
View File
@@ -48,6 +48,14 @@ checkUpdates: true
#
debug: false
#
# Should the "ASL" ASCI art be displayed on plugin startup?
# Setting this to false will hide the banner.
#
# Default: true
#
printBanner: true
#
# Sets how long Favicons should be cached. Value is in minutes with the lowest possible value being 1.
#
@@ -58,6 +66,19 @@ debug: false
#
faviconCacheTime: 1
#
# Sets how AdvancedServerList should handle the size and positioning of images for favicons.
#
# Available options:
#
# - resize: Resizes the image to 64x64 pixels if it isn't these dimensions already.
# - center: Doesn't resize the image, but instead tries to center it as good as possible in a 64x64 area.
# - none: Doesn't resize the image and leaves it positioned at x 0 and y 0 (top-left) of the 64x64 area.
#
# Setting any not listed option or leaving this blank/removing it sets the option to resize.
#
faviconStrategy: 'resize'
#
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
#
@@ -84,6 +105,12 @@ disableDuringMaintenance:
#
hidePlayers: true
#
# Whether hiding player list on hover should be disabled while Maintenance mode is active.
#
# Default: true
#
hidePlayersHover: true
#
# Whether player count text changing should be disabled while Maintenance mode is active.
#
# Default: true
@@ -107,6 +134,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 +147,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}
+60 -14
View File
@@ -10,9 +10,9 @@ priority: 0
# Set condition(s) that should return true to display this profile.
# This allows you to create profiles to only show for specific scenarios (i.e. player is banned).
#
# Multiple conditions can be chaing with the keywords 'and', 'or', or their counterparts '&&' and '||'.
# 'AND'/'&&' and 'OR'/'||' can be used to chain together multiple conditions.
#
# No condition or an empty condition will be treated as true by default.
# Removing the condition option or setting it to an empty String will be treated as a true condition being returned.
#
# Read more: https://asl.andre601.ch/profiles/#condition
#
@@ -40,8 +40,11 @@ profiles:
#
# Set the "Message of the day" to display.
# This option supports RGB colors for 1.16+ Servers and clients, including gradients using MiniMessage's <gradient>
# option.
# This option supports RGB colors for 1.16+ Servers and clients. More advanced MiniMessage features such as <gradient>
# can be used for further styling the text.
#
# <center> can be put at the start of a line to have AdvancedServerList automatically center the text as good as
# possible.
#
# Only the first two lines will be considered and any additional one is ignored.
#
@@ -55,22 +58,30 @@ motd:
#
# Set the Favicon (image on the left of a server entry) to display.
# This option supports three types of inputs:
# This option supports three types of input:
#
# 1. Name, including .png extension, pointing to an image located in the plugin's favicons folder.
# 2. URL pointing to an image.*
# 3. Player name, UUID or placeholders returning one of these.*
# https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
# 1. Filename, including the .png extension, matching a filename in the favicons folder of the plugin.
# - 'random' can be used to have AdvancedServerList select a random image from the favicons folder every time
# the server is pinged.
# 3. URL pointing to an image.
# 4. Player name, UUID or a placeholder that returns either.
# - https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
#
# * These images are loaded asynchronously, meaning they may not yet be "ready" when AdvancedServerList is done with
# the event, requiring a refresh of the server list by the player to have it shown.
#
# Any images above or below 64x64 pixels will be automatically resized to these dimensions.
# Any image below or above 64x64 pixels will be resized according to the faviconResizeMode option in the config.yml.
#
# If not present or empty (favicon: ''), defaults to not modifying the favicon.
#
# Read more: https://asl.andre601.ch/profiles/#favicon
#
# "The favicon isn't showing!"
# This is a side effect of using either URLs or player names/UUIDs for the favicon.
# These types require AdvancedServerList to create a new favicon object from scratch. This action takes a significant
# amount of time, which can cause the server to show with a huge ping.
# To avoid this is this action performed asynchronously. This means that the plugin doesn't wait for the favicon to
# be created before continuing, which can result in no favicon being available when it is done handling the ping.
# This should only happen for the first ping of a player and subsequent pings should display the favicon, if the
# pings are done within the configured cache time (See 'faviconCacheTime' in the config.yml).
#
favicon: ''
#
@@ -90,9 +101,18 @@ playerCount:
#
hidePlayers: false
#
# Set whether the List of players is shown when hovering over the player count.
# Setting this to true will also make the plugin ignore the hover option below.
#
# If not present, defaults to false.
#
# Read more: https://asl.andre601.ch/profiles/#hideplayershover
#
hidePlayersHover: false
#
# Set the lines shown when the player hovers over the player count.
# Unlike the MOTD option does this one only support basic color and formatting codes. Any RGB colors will be
# downsampled to the nearest matching color.
# down-sampled to the nearest matching color.
#
# If not present or empty (hover: []), defaults to not modifying the hover.
#
@@ -134,6 +154,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 +183,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
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.test;
package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.test;
package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.expressionparser.ParseWarnCollector;
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.test;
package ch.andre601.advancedserverlist.core;
import com.unascribed.flexver.FlexVerComparator;
import org.junit.jupiter.api.Test;
+15
View File
@@ -0,0 +1,15 @@
def on_pre_page_macros(env):
footer = """
{% if page.meta and page.meta.api %}
{% include 'api_docs/constructor_summaries.md' %}
{% include 'api_docs/nested_class_summaries.md' %}
{% include 'api_docs/enum_summaries.md' %}
{% include 'api_docs/method_summaries.md' %}
{% include 'api_docs/constructor_details.md' %}
{% include 'api_docs/enum_details.md' %}
{% include 'api_docs/method_details.md' %}
{% endif %}
"""
env.markdown += footer
+23
View File
@@ -0,0 +1,23 @@
import re
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import Files
from mkdocs.structure.pages import Page
from re import Match
def on_page_markdown(
markdown: str, *, page: Page, config: MkDocsConfig, files: Files
):
def replace(match: Match):
platform = match.group(1)
if platform == "paper": return "[:fontawesome-solid-paper-plane:](https://papermc.io){ .md-button .md-button--icon title=\"PaperMC\" target=\"_blank\" rel=\"noopener\" }"
elif platform == "bungee": return "[:simple-spigotmc:](https://spigotmc.org){ .md-button .md-button--icon title=\"BungeeCord\" target=\"_blank\" rel=\"noopener\" }"
elif platform == "velocity": return "[:simple-velocity:](https://velocitypowered.com){ .md-button .md-button--icon title=\"Velocity\" target=\"_blank\" rel=\"noopener\" }"
elif platform == "proxies": return "[:simple-spigotmc:](https://spigotmc.org){ .md-button .md-button--icon title=\"BungeeCord\" target=\"_blank\" rel=\"noopener\" } [:simple-velocity:](https://velocitypowered.com){ .md-button .md-button--icon title=\"Velocity\" target=\"_blank\" rel=\"noopener\" }"
elif platform == "all": return "[:fontawesome-solid-paper-plane:](https://papermc.io){ .md-button .md-button--icon title=\"PaperMC\" target=\"_blank\" rel=\"noopener\" } [:simple-spigotmc:](https://spigotmc.org){ .md-button .md-button--icon title=\"BungeeCord\" target=\"_blank\" rel=\"noopener\" } [:simple-velocity:](https://velocitypowered.com){ .md-button .md-button--icon title=\"Velocity\" target=\"_blank\" rel=\"noopener\" }"
else: return platform
return re.sub(
r"<!-- icon:(paper|bungee|velocity|proxies|all) -->",
replace, markdown, flags = re.I | re.M
)
+1 -1
View File
@@ -17,7 +17,7 @@
import re
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import File, Files
from mkdocs.structure.files import Files
from mkdocs.structure.pages import Page
def on_page_markdown(
-35
View File
@@ -1,35 +0,0 @@
{% extends "base.html" %}
{% import "api-objects/info-template.html" as info %}
{% block content %}
{% include "partials/content.html" %}
{% if page.meta %}
<!--
Object summaries
-->
{% if page.meta.constructors %}
{{ info.summary('Constructor Summary', page.meta.constructors, details_type='constructor', defaults=page.meta.defaults) }}
{% endif %}
{% if page.meta.classes %}
{{ info.summary('Class Summary', page.meta.classes, details_type='class', defaults=page.meta.defaults) }}
{% endif %}
{% if page.meta.enums %}
{{ info.summary('Enum Constant Summary', page.meta.enums, details_type='enum', defaults=page.meta.defaults) }}
{% endif %}
{% if page.meta.methods or page.meta.inherits %}
{{ info.summary('Method Summary', page.meta.methods, page.meta.inherits, details_type='method', defaults=page.meta.defaults) }}
{% endif %}
<!--
Detailed object info
-->
{% if page.meta.constructors %}
{{ info.info('Constructor Detail', page.meta.constructors, 'constructor', defaults=page.meta.defaults) }}
{% endif %}
{% if page.meta.enums %}
{{ info.info('Enum Constant Detail', page.meta.enums, 'enum', defaults=page.meta.defaults) }}
{% endif %}
{% if page.meta.methods %}
{{ info.info('Method Detail', page.meta.methods, 'method', defaults=page.meta.defaults)}}
{% endif %}
{% endif %}
{% endblock %}
@@ -1,228 +0,0 @@
{% macro summary(title, summaries, inherits, details_type = 'unknown', defaults = []) -%}
<h2 id="{{ title | lower() | replace(' ', '-') | e}}">
{{ title }}
</h2>
<div class="md-typeset__scrollwrap">
<div class="md-typeset__table">
{% if summaries %}
<table>
<thead>
<tr>
{% if details_type and details_type == "method" %}
<th>Modifier and Type</th>
{% endif %}
<th>{{ details_type | capitalize() }}</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for summary in summaries %}
<tr>
{% set modifiers = namespace(name = "") %}
{% for attribute in summary.attributes %}
{% set modifiers.name = modifiers.name ~ attribute %}
{% if loop.revindex > 0 %}{% set modifiers.name = modifiers.name ~ " " %}{% endif %}
{% endfor %}
{% if modifiers.name %}{% set modifiers.name = modifiers.name ~ " " %}{% endif %}
{% if summary.type and summary.type.name %}
{% set modifiers.name = modifiers.name ~ summary.type.name %}
{% elif defaults and defaults.type and defaults.type.name %}
{% set modifiers.name = modifiers.name ~ defaults.type.name %}
{% else %}
{% set modifiers.name = modifiers.name ~ "void" %}
{% endif %}
{% set desc = "" %}
{% if summary.deprecated %}
{% set desc = "<api__deprecated></api__deprecated><br>" ~ summary.deprecated.split("<br>")[0] %}
{% elif summary.description %}
{% set desc = summary.description.split("<br>")[0] %}
{% endif %}
{% set final_name = namespace(name = "") %}
{% if details_type and details_type == "enum" %}
{% set final_name.name = summary.name | upper() %}
{% else %}
{% set final_name.name = summary.name ~ "(" %}
{% endif %}
{% for parameter in summary.parameters %}
{% set final_name.name = final_name.name ~ parameter.type %}
{% if loop.revindex > 1 %}{% set final_name.name = final_name.name ~ ", " %}{% endif %}
{% endfor %}
{% if details_type != "enum" %}
{% set final_name.name = final_name.name ~ ")" %}
{% endif %}
{% if details_type and details_type == "method" %}
{% if modifiers.name %}
<td><code>{{ modifiers.name }}</code></td>
{% else %}
<td></td>
{% endif %}
{% endif %}
<td>
{% if summary.link %}
<a href="{{ summary.link }}"><code>{{ final_name.name | e}}</code></a>
{% else %}
<a href="#{{ final_name.name | lower() | replace(' ', '-') | e }}"><code>{{ final_name.name | e}}</code></a>
{% endif %}
</td>
<td>{{ desc }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if inherits %}
{% for classpath, inherit in inherits.items() %}
<table>
<thead>
<tr>
<th>Methods inherited from <a href="{{ inherit.link }}"><code>{{ classpath }}</code></a></th>
</tr>
</thead>
<tbody>
<tr>
<td>
{% for inh in inherit.list %}
<a href="{{ inherit.link }}#{{ inh | lower() | replace(' ', '-') | e }}">
<code>{{- inh | e -}}</code>
</a>
{%- if loop.revindex > 1 %}, {% endif -%}
{% endfor %}
</td>
</tr>
</tbody>
</table>
{% endfor %}
{% endif %}
</div>
</div>
{%- endmacro %}
{% macro info(title, details, details_type = 'unknown', defaults = []) -%}
<h2 id="{{ title | lower() | replace(' ', '-') | e}}">
{{ title }}
</h2>
{% for detail in details %}
<div class="api-detail">
{% set final_name = namespace(name = "") %}
{% if details_type == "enum" %}
{% set final_name.name = detail.name | upper() %}
{% else %}
{% set final_name.name = detail.name ~ "(" %}
{% endif %}
{% for parameter in detail.parameters %}
{% set final_name.name = final_name.name ~ parameter.type %}
{% if loop.revindex > 1 %}{% set final_name.name = final_name.name ~ ", " %}{% endif %}
{% endfor %}
{% if details_type != "enum" %}
{% set final_name.name = final_name.name ~ ")" %}
{% endif %}
<h3 id="{{ final_name.name | lower() | replace(' ', '-') | e }}">
{% if detail.deprecated %}
<api__deprecated></api__deprecated>
{% endif %}
{% for attribute in detail.attributes %}
<api__{{- attribute -}}></api__{{- attribute -}}>
{% endfor %}
{% if enum %}
<api__static></api__static> <api__final></api__final>
{% endif %}
{% if detail.type and details_type == "method" %}
{% if detail.type.link %}
<a href="{{ detail.type.link }}" class="api-type__{{- detail.type.type | default('primitive') -}}">{{ detail.type.name | default('void') | e }}</a>
{% else %}
<span class="api-type__{{- detail.type.type | default('primitive') -}}">{{ detail.type.name | default('void') | e }}</span>
{% endif %}
{% elif defaults and defaults.type and details_type == "method" %}
{% if defaults.type.link %}
<a href="{{ defaults.type.link }}" class="api-type__{{- defaults.type.type | default('primitive') -}}">{{ defaults.type.name | default('void') | e }}</a>
{% else %}
<span class="api-type__{{- defaults.type.type | default('primitive') -}}">{{ defaults.type.name | default('void') }}</span>
{% endif %}
{% elif details_type == "method" %}
<span class="api-type__primitive">void</span>
{% endif %}
<code>{{ final_name.name | e }}</code><a href="#{{ final_name.name | lower() | replace(' ', '-') | e }}" class="headerlink" title="Permanent link"></a>
</h3>
{% if detail.deprecated %}
<div class="admonition deprecated">
<div class="admonition-title">Deprecation Warning</div>
<p>
{{ detail.deprecated }}
</p>
</div>
{% endif %}
{% if detail.description %}
<p class="api-detail__description">
{{ detail.description }}
</p>
{% endif %}
{% if detail.parameters %}
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-parameters">
Parameters:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-parameters" class="headerlink" title="Permanent link"></a>
</h4>
<ul>
{% for parameter in detail.parameters %}
<li>
{% for attribute in parameter.attribute %}
<api__{{- attribute -}}></api__{{- attribute -}}>
{% endfor %}
<code>{{ parameter.type | e }}: {{ parameter.name }}</code>{% if parameter.description %} - {{ parameter.description }}{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% if detail.returns %}
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-returns">
Returns:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-returns" class="headerlink" title="Permanent link"></a>
</h4>
<p class="api-detail__description">
{{ detail.returns }}
</p>
{% endif %}
{% if detail.throws %}
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-throws">
Throws:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-throws" class="headerlink" title="Permanent link"></a>
</h4>
<ul>
{% for throw in detail.throws %}
<li>
<code>{{ throw.name }}</code>{% if throw.description %} - {{ throw.description }}{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% if seealso %}
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-see-also">
See also:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-see-also" class="headerlink" title="Permanent link"></a>
</h4>
<ul>
{% for see in detail.seealso %}
<li>
<a href="{{ see.link }}"><code>{{ see.name }}</code></a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
{%- endmacro %}
@@ -0,0 +1,61 @@
{% if page.meta.constructors %}
## Constructor Details
{% for constructor in page.meta.constructors %}
<div class="api-detail" markdown>
{% set name = namespace(text = constructor.name ~ "(") %}
{% for parameter in constructor.parameters %}
{% set name.text = name.text ~ parameter.type %}
{% if loop.revindex > 1 %}{% set name.text = name.text ~ ", " %}{% endif %}
{% endfor %}
{% set name.text = name.text ~ ")" %}
{% if constructor.deprecated %}
{% set name.text = "<api__deprecated></api__deprecated> " ~ name.text %}
{% endif %}
{% for attribute in constructor.attributes %}
{% set name.text = "<api__{{- attribute -}}></api__{{- attribute -}}> " ~ name.text %}
{% endfor %}
### {{ name.text | e }} { #{{ constructor.name | lower() | replace(' ', '-') | e }} }
{% if constructor.deprecated %}
/// deprecated | Deprecation Warning
{{ constructor.deprecated }}
///
{% endif %}
{% if constructor.description %}
<p class="api-detail__description">
{{ constructor.description }}
</p>
{% endif %}
{% if constructor.parameters %}
#### Parameters: { #{{ constructor.name | lower() | replace(' ', '-') | e }}-parameters }
{% for parameter in constructor.parameters %}
- {% for attribute in parameter.attributes %}<api__{{- attribute -}}></api__{{- attribute -}}>{% endfor %} `{{ parameter.type | e}}: {{ parameter.name }}`{% if parameter.description %} - {{ parameter.description }}{% endif %}
{% endfor %}
{% endif %}
{% if constructor.seealso %}
#### See also: { #{{ constructor.name | lower() | replace(' ', '-') | e }}-see-also }
<div class="api-detail__description" markdown>
{% for see in constructor.seealso %}
- [`{{ see.name }}`]({{ see.link }})
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
{% endif %}
@@ -0,0 +1,14 @@
{% if page.meta.constructors %}
## Constructor Summary
| Constructor | Description |
|-------------|-------------|{% for constructor in page.meta.constructors %}
| [`{{ constructor.name }}({% for parameter in constructor.parameters -%}
{{ parameter.type }}{% if loop.revindex > 1 %}, {% endif %}
{%- endfor %})`](#{{ constructor.name | lower() }}) | {% if constructor.deprecated -%}
<api__deprecated></api__deprecated> {{ constructor.deprecated.split("\n")[0] }}
{%- elif constructor.description -%}
{{ constructor.description.split("\n")[0] }}
{%- endif %} |
{%- endfor %}
{% endif %}
+32
View File
@@ -0,0 +1,32 @@
{% if page.meta.enums %}
## Enum Constant Details
{% for enum in page.meta.enums %}
<div class="api-detail" markdown>
{% set modifiers = namespace(text = "<api__static></api__static> <api__final></api__final> ") %}
{% if enum.deprecated %}
{% set modifiers.text = "<api__deprecated></api__deprecated> " ~ modifiers.text %}
{% endif %}
### {{ modifiers.text }} `{{ enum.name | upper() }}` { #{{ enum.name | lower() | replace(' ', '-') | e }} }
{% if enum.deprecated %}
/// deprecated | Deprecation Warning
{{ enum.deprecated }}
///
{% endif %}
{% if enum.description %}
<div class="api-detail__description" markdown>
{{ enum.description }}
</div>
{% endif %}
</div>
{% endfor %}
{% endif %}
@@ -0,0 +1,8 @@
{% if page.meta.enums %}
## Enum Constant Summary
| Enum | Description |
|------|-------------|{% for enum in page.meta.enums %}
| [`{{ enum.name | upper() }}`](#{{ enum.name | lower() }}) | {{ enum.description.split("\n")[0] }} |
{%- endfor %}
{% endif %}
+3
View File
@@ -0,0 +1,3 @@
{% macro render_name(method) -%}
{{ method.name }}({% for parameter in method.parameters %}{{ parameter.type }}{% if loop.revindex > 1 %}, {% endif %}{% endfor %})
{%- endmacro %}
+109
View File
@@ -0,0 +1,109 @@
{% if page.meta.methods %}
## Method Details
{% for method in page.meta.methods %}
<div class="api-detail" markdown>
{% set modifiers = namespace(text = "") %}
{% if method.deprecated %}
{% set modifiers.text = "<api__deprecated></api__deprecated> " %}
{% endif %}
{% for attribute in method.attributes %}
{% set modifiers.text = modifiers.text ~ "<api__" ~ attribute ~ "></api__" ~ attribute ~ ">" %}
{% if loop.revindex > 0 %}{% set modifiers.text = modifiers.text ~ " " %}{% endif %}
{% endfor %}
{% if modifiers.text %}{% set modifiers.text = modifiers.text ~ " " %}{% endif %}
{% set method_type = "" %}
{% if method.type %}
{% if method.type.link %}
{% set method_type = '[' ~ method.type.name|default('void')|e ~ '](' ~ method.type.link ~ '){ .api-type__' ~ method.type.type|default('primitive') ~ '} ' %}
{% else %}
{% set method_type = '<span class="api-type__' ~ method.type.type|default('primitive') ~ '">' ~ method.type.name|default('void')|e ~ '</span> ' %}
{% endif %}
{% elif page.meta.defaults and page.meta.defaults.type %}
{% if page.meta.defaults.type.link %}
{% set method_type = '[' ~ page.meta.defaults.type.name|default('void')|e ~ '](' ~ page.meta.defaults.type.link ~ '){ .api-type__' ~ page.meta.defaults.type.type|default('primitive') ~ '} ' %}
{% else %}
{% set method_type = '<span class="api-type__' ~ page.meta.defaults.type.type|default('primitive') ~ '">' ~ page.meta.defaults.type.name|default('void')|e ~ '</span> ' %}
{% endif %}
{% else %}
{% set method_type = '<span class="api-type__primitive">void</span> ' %}
{% endif %}
{% set name = namespace(text = method.name ~ "(") %}
{% for parameter in method.parameters %}
{% set name.text = name.text ~ parameter.type %}
{% if loop.revindex > 1 %}{% set name.text = name.text ~ ", " %}{% endif %}
{% endfor %}
{% set name.text = name.text ~ ")" %}
### {{ modifiers.text }} {{ method_type }} `{{ name.text }}` { #{{ method.name | lower() | replace(' ', '-') | e }} }
{% if method.deprecated %}
/// deprecated | Deprecation Warning
{{ method.deprecated }}
///
{% endif %}
{% if method.description %}
<div class="api-detail__description" markdown>
{{ method.description }}
</div>
{% endif %}
{% if method.parameters %}
#### Parameters: { #{{ method.name | lower() | replace(' ', '-') | e }}-parameters }
<div class="api-detail__description" markdown>
{% for parameter in method.parameters %}
- {% for attribute in parameter.attributes %}<api__{{- attribute -}}></api__{{- attribute -}}>{% endfor %} `{{ parameter.type | e}}: {{ parameter.name }}`{% if parameter.description %} - {{ parameter.description }}{% endif %}
{% endfor %}
</div>
{% endif %}
{% if method.returns %}
#### Returns: { #{{ method.name | lower() | replace(' ', '-') | e }}-returns }
<div class="api-detail__description" markdown>
{{ method.returns }}
</div>
{% endif %}
{% if method.throws %}
#### Throws: { #{{ method.name | lower() | replace(' ', '-') | e }}-throws }
<div class="api-detail__description" markdown>
{% for throw in method.throws %}
- `{{ throw.name }}`{% if throw.description %} - {{ throw.description }}{% endif %}
{% endfor %}
</div>
{% endif %}
{% if method.seealso %}
#### See also: { #{{ method.name | lower() | replace(' ', '-') | e }}-see-also }
<div class="api-detail__description" markdown>
{% for see in method.seealso %}
- [`{{ see.name }}`]({{ see.link }})
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
{% endif %}
@@ -0,0 +1,31 @@
{% if page.meta.methods or page.meta.inherits %}
## Method Summary
{% if page.meta.methods %}
| Modifier and Type | Method | Description |
|-------------------|--------|-------------|{% for method in page.meta.methods %}
| `{% if method.attributes -%}
{% for attribute in method.attributes -%}
{{ attribute }}{% if loop.revindex > 0 %} {% endif %}
{%- endfor %} {%- endif %}{% if method.type and method.type.name -%}
{{ method.type.name }}
{%- elif page.meta.defaults and page.meta.defaults.type and page.meta.defaults.type.name -%}
{{ page.meta.defaults.type.name }}
{%- else -%}void{%- endif %}` | [`{{ method.name }}({% for parameter in method.parameters -%}
{{ parameter.type }}{% if loop.revindex > 1 %}, {% endif %}
{%- endfor %})`](#{{ method.name | lower() }}) | {% if method.deprecated -%}
<api__deprecated></api__deprecated> {{ method.deprecated.split("\n")[0] }}
{%- elif method.description -%}
{{ method.description.split("\n")[0] }}
{%- endif %} |
{%- endfor %}
{% endif %}
{% if page.meta.inherits %}
{% for classpath, inherit in page.meta.inherits.items() %}
| Methods inherited from [`{{ classpath }}`]({{ inherit.link }}) |
|----------------------------------------------------------------|
| {% for entry in inherit.list -%}[`{{ entry.name | e }}`]({{ inherit.link }}#{{ entry.link | lower() | replace(' ', '-') | e }}){% if loop.revindex > 1 %}, {% endif %}{% endfor %} |
{% endfor %}
{% endif %}
{% endif %}
@@ -0,0 +1,11 @@
{% if page.meta.classes %}
## Nested Class Summary
| Modifier and Type | Class | Description |
|-------------------|-------|-------------|{% for class in page.meta.classes %}
| `{% if class.attributes -%}
{% for attribute in class.attributes -%}
{{ attribute }}{% if loop.revindex > 1 %} {% endif %}
{%- endfor %} {%- endif %}{{ class.type }}` | [`{{ class.name }}`]({{ class.link }}) | {{ class.description.split("\n")[0] }} |
{%- endfor %}
{% endif %}
+6
View File
@@ -0,0 +1,6 @@
{% extends "base.html" %}
{% block announce %}
<span class="twemoji">{% include ".icons/octicons/paintbrush-24.svg" %}</span>
The <a href="/profiles">Profiles page</a> received a huge restructuring!
{% endblock %}
+10
View File
@@ -0,0 +1,10 @@
[discord]: https://discord.gg/MyPTjpsgGH
[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
[modrinth]: https://modrinth.com/plugin/advancedserverlist
[hangar]: https://hangar.papermc.io/Andre_601/AdvancedServerList
[codeberg]: https://codeberg.org/Andre601/AdvancedServerList
@@ -1,7 +1,14 @@
---
icon: octicons/stop-24
---
# BanPlugins Addon
The BanPlugins Addon was made to provide placeholders for different punishment plugins to use in AdvancedServerList.
/// info
The BanPlugins Addon is available in downloads of AdvancedServerList on [:simple-modrinth: Modrinth](https://modrinth.com/plugin/advancedserverlist) and in [Releases on :simple-codeberg: Codeberg](https://codeberg.org/Andre601/AdvancedServerList/releases).
///
## Placeholders
/// tab | AdvancedBan
@@ -9,8 +16,7 @@ The BanPlugins Addon was made to provide placeholders for different punishment p
**Supported Platforms:**
- :fontawesome-solid-paper-plane: Paper
- :simple-spigotmc: BungeeCord
<!-- icon:paper --> <!-- icon:bungee -->
| Placeholder | Description |
|---------------------------------|------------------------------------------------------------------------------------------|
@@ -50,9 +56,7 @@ motd:
**Supported Platforms:**
- :fontawesome-solid-paper-plane: Paper
- :simple-spigotmc: BungeeCord
- :fontawesome-solid-paper-plane: Velocity
<!-- icon:all -->
| Placeholder | Description |
|---------------------------------|------------------------------------------------------------------------------------------|
@@ -88,9 +92,7 @@ motd:
**Supported Platforms:**
- :fontawesome-solid-paper-plane: Paper
- :simple-spigotmc: BungeeCord
- :fontawesome-solid-paper-plane: Velocity
<!-- icon:all -->
| Placeholder | Description |
|------------------------------|------------------------------------------------------------------------------------------|
+10 -2
View File
@@ -13,7 +13,7 @@ These Addons are made by Andre601 and available together with the plugin downloa
<div class="grid cards" markdown>
- [**BanPlugins**](banplugins.md)
- [**BanPlugins**](first-party/banplugins.md)
----
@@ -25,4 +25,12 @@ These Addons are made by Andre601 and available together with the plugin downloa
Third-party addons made by other people not working on AdvancedServerList.
*Currently no entries*
<div class="grid cards" markdown>
- [**SayanVanish**](third-party/sayanvanish.md)
----
SayanVanish adds additional placeholders to the Velocity version of AdvancedServerList to use.
</div>
+43
View File
@@ -0,0 +1,43 @@
---
icon: octicons/eye-closed-24
---
# SayanVanish
The plugin [SayanVanish]{ target="_blank" rel="nofollow" } is hooking into AdvancedServerList to provide placeholders of its own to be used in conditions and text options.
## Placeholders
/// tab | :fontawesome-solid-paper-plane: Paper
[:octicons-file-code-24: Source][source-paper]
| Placeholder | Description |
|----------------------------------|--------------------------------------------------------------------------------------------|
| `${sayanvanish vanished}` | Returns true or false based on if the player is vanished. |
| `${sayanvanish level}` | Returns the vanish level of the player. |
| `${sayanvanish count}` | Returns the number of online players that are vanished. |
| `${sayanvanish online_here}` | Returns the number of online players on the same server that aren't vanished. |
| `${sayanvanish online_total}` | Returns the number of online players on the entire network that aren't vanished.^[1](#n1)^ |
| `${sayanvanish online_<server>}` | Returns the number of online players on `<server>` that aren't vanished.^[1](#n1)^ |
| `${sayanvanish vanish_prefix}` | Returns the prefix for the player while they are vanished or an empty String. |
| `${sayanvanish vanish_suffix}` | Returns the suffix for the player while they are vanished or an empty String. |
<small>^1^{ #n1 } Only works when Proxy mode is enabled and will otherwise return `PROXY_MODE IS NOT ENABLED!`</small>
///
/// tab | :simple-velocity: Velocity
[:octicons-file-code-24: Source][source-velocity]
| Placeholder | Description |
|----------------------------------|----------------------------------------------------------------------------------|
| `${sayanvanish vanished}` | Returns true or false based on if the player is vanished. |
| `${sayanvanish level}` | Returns the vanish level of the player. |
| `${sayanvanish count}` | Returns the number of online players that are vanished. |
| `${sayanvanish online_total}` | Returns the number of online players on the entire network that aren't vanished. |
| `${sayanvanish online_<server>}` | Returns the number of online players on `<server>` that aren't vanished. |
| `${sayanvanish vanish_prefix}` | Returns the prefix for the player while they are vanished or an empty String. |
| `${sayanvanish vanish_suffix}` | Returns the suffix for the player while they are vanished or an empty String. |
///
[SayanVanish]: https://modrinth.com/plugin/sayanvanish
[source-paper]: https://github.com/Syrent/SayanVanish/blob/6e03b874464a7f07c0baba233c94cdfefab5d3e2/sayanvanish-bukkit/src/main/kotlin/org/sayandev/sayanvanish/bukkit/feature/features/hook/FeatureHookAdvancedServerList.kt
[source-velocity]: https://github.com/Syrent/SayanVanish/blob/6e03b874464a7f07c0baba233c94cdfefab5d3e2/sayanvanish-proxy/sayanvanish-proxy-velocity/src/main/kotlin/org/sayandev/sayanvanish/velocity/feature/features/hook/FeatureHookAdvancedServerList.kt
+183
View File
@@ -0,0 +1,183 @@
---
icon: octicons/plus-circle-24
---
AdvancedServerList allows you to add your own Placeholders to be useable through its `${identifier value}` format.
The benefit of this method over alternatives such as using PlaceholderAPI placeholders is availability and the fact that these placeholders can be used within the [`condition` option](../profiles/options/condition.md) of the plugin.
Adding your own placeholder is relatively easy and only requires the main API module to be used in your dependencies, unless you need platform-specific values (Explained later on).
## Create your PlaceholderProvider class
AdvancedServerList's placeholder system uses a dedicated [`PlaceholderProvider`](reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md) class where the placeholder gets defined and its values parsed.
In order to add your own, you'll need to first create a new class and make it extend the `PlaceholderProvider` class:
```java title="MyPlaceholder.java"
public class MyPlaceholder extends PlaceholderProvider {
}
```
Your IDE should now report issues, namely a missing method to override and a missing Constructor to match the extended class' one. Your IDE should allow you to easily implement those, if not, then manually add the constructor with a `String` argument and the `public String parsePlaceholder` method with `String`, [`GenericPlayer`](reference/api/ch.andre601.advancedserverlist.api/objects/genericplayer.md) and [`GenericServer`](reference/api/ch.andre601.advancedserverlist.api/objects/genericserver.md) arguments:
```java { title="MyPlaceholder.java" .annotate }
public class MyPlaceholder extends PlaceholderProvider {
public MyPlaceholder(String identifier) {
super(identifier); // (1)
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
return null;
}
}
```
1. It is recommended to replace the Constructor with a No-Args Constructor and set the placeholder name directly in the `super` call:
```java
public MyPlaceholder() {
super("myplaceholder");
}
```
## Parsing placeholders
To now parse your placeholders, all you need to do is edit the `parsePlaceholder` method.
AdvancedServerList calls this method whenever it finds a matching identifier of a PlaceholderProvider, with the `String` argument being the actual value after the identifier and the `GenericPlayer` and `GenericServer` arguments holding the Player and server values respectively.
As an example, assuming you simply want to return `Hello` for the placeholder `${myplaceholder sayHello}`, this would be the code for it:
```java { title="MyPlaceholder.java" .annotate }
public class MyPlaceholder extends PlaceholderProvider {
public MyPlaceholder() {
super("myplaceholder");
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
if (placeholder.equals("sayHello")) {
return "Hello";
}
return null; // (1)
}
}
```
1. Returning `null` tells AdvancedServerList that the placeholder was invalid, making it return the placeholder unchanged, while also reporting an error, if used in `condition`.
## Registering the Placeholder
The final step now would be to register your placeholder for AdvancedServerList to use.
To do this, obtain an instance of the [`AdvancedServerListAPI`](reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md) through its static `get()` method and then call `addPlaceholderProvider(PlaceholderProvider)` through it:
/// tab | :fontawesome-solid-paper-plane: Paper Example
```java title="MyPlugin.java"
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
AdvancedServerListAPI api = AdvancedServerListAPI.get();
api.addPlaceholderProvider(new MyPlaceholder());
getLogger().info("Hooked into AdvancedServerList!");
}
}
```
///
/// tab | :octicons-git-merge-24: BungeeCord Example
```java title="MyPlugin.java"
public class MyPlugin extends Plugin {
@Override
public void onEnable() {
AdvancedServerListAPI api = AdvancedServerListAPI.get();
api.addPlaceholderProvider(new MyPlaceholder());
getLogger().info("Hooked into AdvancedServerList!");
}
}
```
///
/// tab | :simple-velocity: Velocity Example
```java title="MyPlugin.java"
@Plugin(
id = "myplugin",
version = "1.0.0",
authors = {"You?"},
dependencies = {
@Dependency(id = "advancedserverlist")
}
)
public class MyPlugin {
private final ProxyServer proxy;
private final Logger logger;
@Inject
public MyPlugin(ProxyServer proxy, Logger logger) {
this.proxy = proxy;
this.logger = logger;
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
AdvancedServerListAPI api = AdvancedServerListAPI.get();
api.addPlaceholderProvider(new MyPlaceholder());
logger.info("Hooked into AdvancedServerList!");
}
}
```
///
## You're done
Your Placeholders should now be registered successfully if they check the following:
- The provided identifier is not `null` nor empty.
- The provided identifier does not contain spaces.
- The provided identifier is not already registered in the API.
## Note on `GenericPlayer` and `GenericServer`
The different platform APIs of AdvancedServerList provide extended versions of the `GenericPlayer` and `GenericServer` instances used, providing additional methods otherwise not available.
Should you want to use these specific instances will you need to add the platform API as an additional dependency to your project and then cast the `GenericPlayer` and/or `GenericServer` instance to the platform specific version.
Below is an example using the `platform-bukkit` API (This assumes your plugin is one running on Paper):
```java { title="MyPlaceholder.java" .annotate }
public class MyPlaceholder extends PlaceholderProvider {
public MyPlaceholder() {
super("myplaceholder");
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
if (!(player instanceof BukkitPlayer bukkitPlayer)) {
return null; // (1)
}
return switch (placeholder) {
case "playedBefore" -> String.valueOf(bukkitPlayer.hasPlayedBefore());
case "whitelisted" -> String.valueOf(bukkitPlayer.isWhitelisted());
case "banned" -> String.valueOf(bukkitPlayer.isBanned());
default -> null;
};
}
}
```
1. Depending on the Java version you use will you need to alter the code:
```java
if (!(player instanceof BukkitPlayer)) {
return null;
}
// You need to cast it separately.
BukkitPlayer bukkitPlayer = (BukkitPlayer) player;
// ...use bukkitPlayer here.
```
+40 -17
View File
@@ -7,6 +7,32 @@ icon: octicons/log-24
This page lists the recent changes made towards the AdvancedServerListAPI.
They are ordered newest to oldest.
## v4.1.0 { #v4.1.0 }
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v-added }
- New setter method added to [`ProfileEntry.Builder`][profileentry.builder] class:
- [`hidePlayersHoverEnabled(NullBool)`][hidePlayersHoverEnabled]
[hidePlayersHoverEnabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#hideplayershoverenabled
## 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`][profileentry.builder] class:
- [`onlinePlayersCount(String)`][onlinePlayersCount]
- [`onlinePlayersEnabled(NullBool)`][onlinePlayersEnabled]
[onlinePlayersCount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayerscount
[onlinePlayersEnabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayersenabled
## v3.3.0 { #v3.3.0 }
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3.3.0-added }
@@ -36,15 +62,15 @@ They are ordered newest to oldest.
- [`playerCountText(String)`][playercounttext]
- [`players(List<String>)`][players]
[extraplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayerscount(integer)
[extraplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayersenabled(nullbool)
[favicon]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#favicon(string)
[hideplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#hideplayersenabled(nullbool)
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayerscount(integer)
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayersenabled(nullbool)
[motd]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#motd(list<string>)
[playercounttext]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#playercounttext(string)
[players]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#players(list<string>)
[extraplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayerscount
[extraplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayersenabled
[favicon]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#favicon
[hideplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#hideplayersenabled
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayerscount
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayersenabled
[motd]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#motd
[playercounttext]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#playercounttext
[players]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#players
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v3.2.0-changed }
@@ -102,22 +128,19 @@ They are ordered newest to oldest.
- [`maxPlayersEnabled()`][maxplayersenabled] - Returns the value for `playerCount -> maxPlayers -> enabled` as `NullBool`
- [`maxPlayersCount()`][maxplayerscount] - Returns the value of `playerCount -> maxPlayers -> amount` as nullable `Integer`
- New setters in [`ProfileEntry.Builder`][profileentry.builder]:
- [`setMaxPlayersEnabled(NullBool)`][setmaxplayersenabled] - Sets whether the max players feature is enabled or not.
- [`setMaxPlayersCount(Integer)`][setmaxplayerscount] - Sets the number to use for the max players count.
- [`setExtraPlayersCount(Integer)`][setextraplayersecount] - Replacement for [deprecated `setExtraPlayerCount(Integer)` method](#v3.1.0-deprecated).
- `setMaxPlayersEnabled(NullBool)`- Sets whether the max players feature is enabled or not.
- `setMaxPlayersCount(Integer)` - Sets the number to use for the max players count.
- `setExtraPlayersCount(Integer)` - Replacement for [deprecated `setExtraPlayerCount(Integer)` method](#v3.1.0-deprecated).
### :octicons-zap-24:{ .changelog-breaking title="Deprecated" } Deprecated { #v3.1.0-deprecated }
- `setExtraPlayerEnabled(Integer)` in `ProfileEntry.Builder` - Typo in method name.
[profileentry]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayersenabled()
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayerscount()
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayersenabled
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayerscount
[profileentry.builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
[setmaxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setmaxplayersenabled(nullbool)
[setmaxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setmaxplayerscount(integer)
[setextraplayersecount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setextraplayerscount(integer)
----
+12 -166
View File
@@ -11,7 +11,7 @@ AdvancedServerList offers an API that other plugins can use to add their own pla
Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depending on what you use:
/// tab | :simple-apachemaven: Maven
```xml title="pom.xml"
```xml { data-md-component="api-version" title="pom.xml" }
<repositories>
<repository>
<id>codeberg</id>
@@ -51,7 +51,7 @@ Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depend
///
/// tab | :simple-gradle: Gradle
```groovy title="build.gradle"
```groovy { data-md-component="api-version" title="build.gradle" }
repositorories {
maven { url = 'https://codeberg.org/api/packages/Andre601/maven/' }
}
@@ -68,7 +68,7 @@ dependencies {
///
/// tab | :simple-gradle: Gradle (KTS)
```kotlin title="build.gradle.kts"
```kotlin { data-md-component="api-version" title="build.gradle.kts" }
repositories {
maven("https://codeberg.org/api/packages/Andre601/maven/")
}
@@ -84,129 +84,21 @@ dependencies {
```
///
## Adding your own Placeholders
## Tutorials
<!-- admo:info This requires the main api module -->
Dedicated pages to explain aspects of the API are available:
The API allows you to add your own placeholders which would be available through the `${<identifier> <values>}` placeholder Pattern in a Server List profile.
To add your own placeholders, follow these steps:
### 1. Create a Placeholder class
You should first create a new class and make it extend the abstract [`PlaceholderProvider`][placeholderprovider]. This class includes a constructor and a method you need to add, so do that:
```java
public class MyPlaceholders extends PlaceholderProvider {
public MyPlaceholders(String identifier) {
super(identifier);
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
return null;
}
}
```
/// tip
You can replace the Constructor with a String argument with a no-args constructor and set the identifier directly in the `super`:
```java
public MyPlaceholders() {
super("myplaceholders");
}
```
/// html | div.grid.cards
- [:octicons-plus-circle-24: Adding Placeholders](adding-placeholders.md)
- [:octicons-broadcast-24: Listening for Events](listening-for-events.md)
///
The [`parsePlaceholder(String, GenericPlayer, GenericServer)`][parseplaceholder] method is used by AdvancedServerList to replace a matching placeholder with a value.
What you return is completely up to you. Just keep in mind that returning `null` will be treated as an invalid placeholder by AdvancedServerList, resulting in the placeholder being returned as-is without any changes.
[placeholderprovider]: reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md
[parseplaceholder]: reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md#parseplaceholder(string,-genericplayer,-genericserver)
/// details | Example of final class
type: example
```java
public class MyPlaceholders extends PlaceholderProvider {
public MyPlaceholders() {
super("myplaceholders");
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
if(placeholder.equalsIgnoreCase("hello"))
return "Hello " + player.getName();
return null;
}
}
```
///
### 2. Register the Placeholders
Next step should be to register the placeholder. To achieve this, first obtain an instance of the [`AdvancedServerListAPI`][advancedserverlistapi] by using the static [`get()`][get] method. After that call [`addPlaceholderProvider(PlaceholderProvider placeholderProvider)`][addplaceholderprovider].
Your code may look similar to this:
```java title="Registering PlaceholderProvider class"
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
AdvancedServerListAPI api = AdvancedServerListAPI.get();
api.addPlaceholderProvider(new MyPlaceholders());
}
}
```
[advancedserverlistapi]: reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md
[get]: reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md#get()
[addplaceholderprovider]: reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md#addplaceholderprovider(placeholderprovider)
This should register your PlaceholderExpansion as long as it is valid, meaning that the identifier...
- ...is not `null`
- ...is not containing spaces
- ...is not using a name already registered in the API
### 3. Declare AdvancedServerList as (soft)depend
## Declare AdvancedServerList as (soft)depend
The final thing you should make sure is to define AdvancedServerList as a depend or soft-depend for your plugin, to make sure it loads after AdvancedServerList.
Below are example setups for Spigot, Paper, BungeeCord and Velocity:
/// tab | :simple-spigotmc: Spigot
//// tab | Softdepend
```yaml title="plugin.yml"
name: "MyPlugin"
author: "author"
version: "1.0.0"
main: "com.example.plugin.ExamplePlugin"
softdepend:
- AdvancedServerList
```
////
//// tab | Depend
```yaml title="plugin.yml"
name: "MyPlugin"
author: "author"
version: "1.0.0"
main: "com.example.plugin.ExamplePlugin"
depend:
- AdvancedServerList
```
////
///
/// tab | :fontawesome-solid-paper-plane: Paper
//// tab | Softdepend
```yaml title="paper-plugin.yml"
@@ -241,7 +133,7 @@ dependencies:
////
///
/// tab | :octicons-git-merge-24: BungeeCord
/// tab | :simple-spigotmc: BungeeCord
//// tab | Softdepend
```yaml title="bungee.yml"
name: "MyPlugin"
@@ -269,7 +161,7 @@ depends:
////
///
/// tab | :octicons-git-merge-24: Velocity
/// tab | :simple-velocity: Velocity
//// tab | Softdepend (File)
```json title="velocity-plugin.json"
{
@@ -357,50 +249,4 @@ public class MyPlugin {
### 4. You're done!
Your plugin should now hook into AdvancedServerList and register its own custom placeholders to use.
## Listening for events
<!-- admo:info These events require the platform-specific APIs -->
AdvancedServerList provides Events that your plugin can listen for specific situations.
### PreServerListSetEvent
This event is called **before** AdvancedServerList starts handling the PingEvent of the Server/Proxy.
It allows you to get and alter the [ProfileEntry][profileentry] used in the PingEvent, or even outright cancel the event itself.
The event offers the following methods:
- [`getEntry()`][getentry] - Gets the currently set [`ProfileEntry`][profileentry].
- [`setEntry(ProfileEntry)`][setentry] - Sets a new [`ProfileEntry`][profileentry] to use.
- [`isCancelled()`][iscancelled] - Gets the current cancelled state of the event.
- [`setCancelled(boolean)`][setcancelled] - Sets the current cancelled state.
Please check the server/proxy's documentation on how to listen for events with your plugin.
[getentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#getentry()
[setentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setentry(profileentry)
[iscancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#iscancelled()
[setcancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setcancelled(boolean)
### PostServerListSetEvent
This event is called **after** AdvancedServerList has completed its handling of the Server's/Proxy's PingEvent.
It provides a method to retrieve the [ProfileEntry][profileentry] used during the PingEvent.
Do note that this ProfileEntry is **not** a representation of what is actually displayed in the server list, but rather what has been used by AdvancedServerList. It may also be `null` should the event handling get cancelled for any reason.
[profileentry]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
### ProfileEntry
The ProfileEntry record is the core class used within the `PreServerListSetEvent`. It sets what values (MOTD, Favicon, Players, etc.) should be displayed.
Note that the record is - by nature - immutable and that the [`Builder`][builder] class should be used to create a new ProfileEntry instance to use.
A convenience method ([`builder()`][builder()]) exists to create a `Builder` instance from an existing `ProfileEntry` in case you only want to alter certain options while everything else should remain unchanged.
This allows you to customize the Server list using your plugin. Just keep in mind that other plugins may also do the same, overriding your changes.
[builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
[builder()]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#builder()
Your plugin should now hook into AdvancedServerList and register its own custom placeholders to use.
+170
View File
@@ -0,0 +1,170 @@
---
icon: octicons/broadcast-24
---
AdvancedServerList provides some events that your plugin can listen to.
These events are structurally the same across all platforms, yet still require the usage of Platform-specific APIs due to how some events are registered and handled on some platforms.
The plugin currently offers the following events:
/// html | div.grid.cards
- [PreServerListSetEvent](#preserverlistsetevent)
- [PostServerListSetEvent](#postserverlistsetevent)
///
## PreServerListSetEvent
This event is executed before AdvancedServerList tries to modify the player list.
### Methods { #preserverlistsetevent-methods }
The following methods are available to use:
| Method | Description |
|-----------------------------------------|--------------------------------------------------------------------------------|
| [`getEntry()`][getentry] | Returns the [`ProfileEntry`][profileentry] that AdvancedServerList should use. |
| [`setEntry(ProfileEntry)`][setentry] | Sets the [`ProfileEntry`][profileentry] that should be used. |
| [`isCancelled()`][iscancelled] | Returns wether this event was cancelled or not. |
| [`setCancelled(boolean)`][setcancelled] | Sets the event's cancelled state. |
[setentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setentry
[iscancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#iscancelled
[setcancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setcancelled
### Notes { #preserverlistsetevent-notes }
- Providing `null` as the `ProfileEntry` for `setEntry(ProfileEntry)` is not allowed. Also, a copy of the provided `ProfileEntry` is made and used.
## PostServerListSetEvent
This event is executed after AdvancedServerList completed the server list modifications.
### Methods { #postserverlistsetevent-methods }
| Method | Description |
|--------------------------|--------------------------------------------------------------------------|
| [`getEntry()`][getentry] | Returns the [`ProfileEntry`][profileentry] that AdvancedServerList used. |
[getentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#getentry
### Notes { #postserverlistsetevent-notes }
- The returned `ProfileEntry` is not an actual representation of what is being displayed to the player and rather an instance of values the plugin received.
The returned value may also be `null` should the Ping Event be cancelled due to things such as an invalid Protocol or the [`PreServerListSetEvent`](#preserverlistsetevent) being cancelled.
## Registering the Events
/// tab | :fontawesome-solid-paper-plane: Paper
```java { title="MyPlugin.java" .annotate }
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
// (1)
Bukkit.getPluginManager().registerEvents(new ASLEventListener(), this);
}
}
```
1. `getServer()` from the `JavaPlugin` class can be used here too instead of the `Bukkit` singleton.
```java { title="ASLEventListener.java" }
public class ASLEventListener implements Listener {
@EventHandler
public void onPreServerListSet(PreServerListSetEvent event) {
System.out.println("PreServerListSetEvent fired!");
}
@EventHandler
public void onPostServerListSetEvent(PostServerListSetEvent event) {
System.out.println("PostServerListSetEvent fired!");
}
}
```
///
/// tab | :simple-spigotmc: BungeeCord
```java { title="MyPlugin.java" }
public class MyPlugin extends Plugin {
@Override
public void onEnable() {
getProxy().getPluginManager().registerListener(this, new ASLEventListener());
}
}
```
```java { title="ASLEventListener.java" }
public class ASLEventListener implements Listener {
@EventHandler
public void onPreServerListSet(PreServerListSetEvent event) {
System.out.println("PreServerListSetEvent fired!");
}
@EventHandler
public void onPostServerListSetEvent(PostServerListSetEvent event) {
System.out.println("PostServerListSetEvent fired!");
}
}
```
///
/// tab | :simple-velocity: Velocity
```java { title="MyPlugin.java" }
@Plugin(
id = "myplugin",
name = "MyPlugin",
version = "1.0.0",
authors = {"author"},
dependencies = {
@Dependency(
id = "advancedserverlist",
)
}
)
public class MyPlugin {
private final ProxyServer proxy;
@Inject
public MyPlugin(ProxyServer server) {
this.proxy = proxy;
}
@Subscribe
public void init(ProxyInitializeEvent event) {
proxy.getEventManager().register(this, new ASLEventListener());
}
}
```
```java { title="ASLEventListener.java" }
public class ASLEventListener {
@Subscribe
public void onPreServerListSet(PreServerListSetEvent event) {
System.out.println("PreServerListSetEvent fired!");
}
@Subscribe
public void onPostServerListSetEvent(PostServerListSetEvent event) {
System.out.println("PostServerListSetEvent fired!");
}
}
```
///
## What is a ProfileEntry?
Both events provide and use a so called [`ProfileEntry`][profileentry].
The `ProfileEntry` is a record, representing the values of a [Server List Profile](../profiles/index.md), meaning all values you can set in the profile configuration (Except condition and priority) will be available as a `ProfileEntry`.
It is important to note, that the `ProfileEntry` can be a representation of the [`profiles` option](../profiles/index.md#profiles), the global options or a mixture of both.
If you want to create your own instance, you'll need to use the [`ProfileEntry.Builder` class](reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md) as the `ProfileEntry` is unmodifiable.
A convenience method in the form of [`builder()`][builder] exists to create a Builder instance of the ProfileEntry with its values already pre-set.
[profileentry]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
[builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#builder
@@ -1,10 +1,10 @@
---
template: api-doc.html
api: true
methods:
- name: 'get'
description: |
Retrieve the instance used of this API.<br>
Retrieve the instance used of this API.
If no instance has been made so far will a new one be created.
returns: 'Instance of this API.'
attributes:
@@ -14,38 +14,38 @@ methods:
type: 'object'
- name: 'addPlaceholderProvider'
description: |
Adds the provided <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> to the list, if it passes the following checks:<br>
<ul>
<li>Provided PlaceholderProvider instance is not null.</li>
<li>The identifier is not null nor empty.</li>
<li>The identifier does not contain any spaces.</li>
<li>A PlaceholderProvider with the same identifier doesn't exist already.</li>
</ul>
Not passing any of the above checks results in a <a href="./../exceptions/invalidplaceholderproviderexception/"><code>InvalidPlaceholderProviderException</code></a> being thrown.
Adds the provided [`PlaceholderAPIProvider`](placeholderprovider.md) to the list, if it passes the following checks:
- Provided PlaceholderProvider instance is not null.
- The identifier is not null nor empty.
- The identifier does not contain any spaces.
- A PlaceholderProvider with the same identifier doesn't exist already.
Not passing any of the above checks results in a [`InvalidPlaceholderProviderException`](exceptions/invalidplaceholderproviderexception.md) being thrown.
parameters:
- name: 'placeholderProvider'
description: 'The <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> to add.'
description: 'The [`PlaceholderProvider`](placeholderprovider.md) to add.'
type: PlaceholderProvider
attributes:
- notnull
throws:
- name: 'InvalidPlaceholderProviderException'
description: 'When the provided <a href="./../placeholderprovider/"><code>PlaceholderProvider</code> instance</a> is null, has a null or empty identifier, the identifier contains spaces, or another PlaceholderProvider with the same identifier is already in use.'
description: 'When the provided [`PlaceholderProvider`](placeholderprovider.md) is null, has a null or empty identifier, the identifier contains spaces, or another PlaceholderProvider with the same identifier is already in use.'
type:
name: 'void'
- name: 'retrievePlaceholderProvider'
description: 'Retrieves the <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> associated with the provided identifier, or <code>null</code> should no such entry exist.'
description: 'Retrieves the [`PlaceholderProvider`](placeholderprovider.md) associated with the provided identifier, or `null` should no such entry exist.'
parameters:
- name: 'identifier'
description: 'The identifier to find a matching <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> for.'
description: 'The identifier to find a matching [`PlaceholderProvider`](placeholderprovider.md) for.'
type: String
returns: 'Possibly-null <a href="./../placeholderprovider/"><code>PlaceholderProvider</code> instance</a>.'
returns: 'Possibly-null [`PlaceholderProvider` instance](placeholderprovider.md).'
attributes:
- nullable
type:
name: PlaceholderProvider
type: object
link: './../placeholderprovider'
link: 'placeholderprovider.md'
---
# <api__class></api__class> AdvancedServerListAPI
@@ -1,27 +1,27 @@
---
template: api-doc.html
api: true
methods:
- name: 'getEntry'
description: 'Gets the <a href="../../profiles/profileentry/"><code>ProfileEntry</code></a> currently set.'
description: 'Gets the [`ProfileEntry`](../profiles/profileentry/index.md) currently set.'
returns: The currently used ProfileEntry.
type:
name: ProfileEntry
type: object
link: '../../profiles/profileentry/'
link: '../profiles/profileentry/index.md'
- name: 'setEntry'
description: |-
Sets the new <a href="../../profiles/profileentry/"><code>ProfileEntry</code></a> to use.<br>
This may not be <code>null</code>.
Sets the new [`ProfileEntry`](../profiles/profileentry/index.md) to use.
This may not be `null`.
parameters:
- name: 'entry'
description: 'The new <a href="../../profiles/profileentry/"><code>ProfileEntry</code></a> to use.'
description: 'The new [`ProfileEntry`](../profiles/profileentry/index.md) to use.'
type: ProfileEntry
attributes:
- notnull
throws:
- name: 'IllegalArgumentException'
description: 'When the provided ProfileEntry is <code>null</code>'
description: 'When the provided ProfileEntry is `null`'
type:
name: 'void'
- name: 'isCancelled'
@@ -1,11 +1,13 @@
---
template: 'api-doc.html'
api: true
constructors:
- name: 'InvalidPlaceholderProviderException'
description: Basic Constructor to create an instance of this Exception.
parameters:
- name: msg
type: String
description: The reason of the exception.
---
# <api__class></api__class> InvalidPlaceholderProviderException
@@ -1,29 +1,27 @@
---
template: api-doc.html
api: true
methods:
- name: 'getName'
description: |
Returns the name of the player.<br>
Note that on Spigot, Paper and other forks can the name differ from the one cached by AdvancedServerList, if the plugin was able to retrieve an OfflinePlayer instance from the server. On BungeeCord and Velocity will the returned String always be the name from the cache.<br>
<br>
Name may be whatever has been defined in AdvancedServerList's config.yml, should the player not be cached yet by the plugin.
Returns the name of the player.
On BungeeCord and Velocity is the returned value always what AdvancedServerList has cached, while on paper the value may differ, should the plugin be able to obtain a OfflinePlayer instance from the Server.
Name may also be whatever has been defined in AdvancedServerList's `unknownPlayer -> name` config.yml Option.
returns: 'String representing the player''s name'
type:
name: String
type: object
- name: 'getProtocol'
description: |
Returns the protocol ID the player is using.<br>
The protocol ID is an integer used by Minecraft to determine what version a server or client is running.
description: Returns the protocol ID the player is using. The protocol ID is a unique positive integer that is used in Minecraft to determine the Version used by the Client and Server.
returns: 'Integer representing the protocol version of this player.'
type:
name: int
- name: 'getUUID'
description: |
Returns the unique ID associated with this player.<br>
<br>
UUID may be whatever has been defined in AdvancedServerList's config.yml, should the player not be cached yet by AdvancedServerList.
Returns the unique ID associated with this player.
UUID may also be whatever has been defined in AdvancedServerList's `unknownPlayer -> uuid` config.yml Option.
returns: 'UUID of the player'
type:
name: UUID
@@ -32,11 +30,11 @@ methods:
# <api__interface></api__interface> GenericPlayer
A basic interface used to store generic player data to use in placeholder resolving.
The different variants of AdvancedServerList implement this into their own class and may provide additional data not available through this interface.
Interface used by the API to share common information across all platforms.
The following values will always be present, no matter the platform this interface is used on:
Platform-specific interfaces extending this interface are available and may offer additional features in addition to what this interface is offering.
This interface always offers data for the following:
- [Name of the Player](#getname())
- [Protocol version of the Player](#getprotocol())
- [UUID of the Player](#getuuid())
- [Name of the Player](#getname)
- [Protocol version of the Player](#getprotocol)
- [UUID of the Player](#getuuid)
@@ -1,5 +1,5 @@
---
template: api-doc.html
api: true
methods:
- name: 'getPlayersOnline'
@@ -24,4 +24,11 @@ methods:
# <api__interface></api__interface> GenericServer
Simple class used to wrap around some generic server data such as online player count, number of total players that can join and the host (IP/Domain) that got pinged by the player.
Interface used to share common information across all platforms.
Platform-specific interfaces extending this interface are available and may offer additional features in addition to what this interface is offering.
This interface always offers data for the following:
- [Players currently online on the Proxy/Server](#getplayersonline)
- [Max Players allowed to join the Proxy/Server](#getplayersmax)
- [IP/Domain pinged by the Player](#gethost)
@@ -1,23 +1,23 @@
---
template: api-doc.html
api: true
enums:
- name: 'true'
description: 'Boolean value <code>true</code>'
description: 'Boolean value `true`'
- name: 'false'
description: 'Boolean value <code>false</code>'
description: 'Boolean value `false`'
- name: 'not_set'
description: 'Boolean value <code>null</code>'
description: 'Boolean value `null`'
methods:
- name: 'resolve'
description: |
Returns a NullBool instance based on the provided <code>Boolean</code> value.<br>
In case of <code>null</code> being provided will <a href="#not_set"><code>NullBool.NOT_SET</code></a> be returned, otherwise will the corresponding NullBool instance matching the Boolean value be returned.
returns: 'NullBool instance based on the provided <code>Boolean</code> value.'
Returns a NullBool instance based on the provided `Boolean` value.
In case of `null` being provided will [`NullBool.NOT_SET`](#not_set) be returned, otherwise will the corresponding NullBool instance matching the Boolean value be returned.
returns: 'NullBool instance based on the provided `Boolean` value.'
parameters:
- name: 'bool'
description: 'The <code>Boolean</code> value to receive a NullBool instance for.'
description: 'The `Boolean` value to receive a NullBool instance for.'
type: Boolean
attributes:
- nullable
@@ -27,19 +27,19 @@ methods:
name: 'NullBool'
type: 'object'
- name: 'isNotSet'
description: 'Returns whether the NullBool is <a href="#not_set"><code>NullBool.NOT_SET</code></a>.'
returns: 'True if the instance is <a href="#not_set"><code>NullBool.NOT_SET</code></a>, otherwise false.'
description: 'Returns whether the NullBool is [`NullBool.NOT_SET`](#not_set)'
returns: 'True if the instance is [`NullBool.NOT_SET`](#not_set), otherwise false.'
type:
name: 'boolean'
type: 'primitive'
- name: 'getOrDefault'
description: |
Gets the corresponding boolean value associated with the NullBool instance.<br>
In the case of NullBool <a href="#isnotset()">not being set</a> will the provided default value be returned.
Gets the corresponding boolean value associated with the NullBool instance.
In the case of NullBool [not being set](#isnotset) will the provided default value be returned.
returns: 'True or false depending on the NullBool instance and the provided default value.'
parameters:
- name: 'def'
description: 'The default boolean value to return should the NullBool instance be <a href="#not_set"><code>NullBool.NOT_SET</code></a>.'
description: 'The default boolean value to return should the NullBool instance be [`NullBool.NOT_SET`](#not_set).'
type: boolean
type:
name: 'boolean'
@@ -48,4 +48,4 @@ methods:
# <api__enum></api__enum> NullBool
Enum used to return a `Boolean` value with a default one should no value be set.
Enum used to return a [`Boolean`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Boolean.html){ target="_blank" rel="noopener" } Value with a fallback, should the boolean be `null`.
Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff. Show more