Compare commits

...
142 Commits
Author SHA1 Message Date
Andre601 1e9c042795 Bump Plugin version 2026-09-27 15:50:09 +02:00
Andre601 1f4672a6a2 Add logs field to bug report template 2026-09-27 15:31:14 +02:00
Andre601 8a60206af6 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.6.4' (#628) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/628
2026-09-26 14:34:13 +02:00
Andre601's Bot 51b0123e5d Update dependency ch.qos.logback:logback-classic to v1.6.4 2026-09-26 12:03:56 +00:00
Andre601 c2c6dde058 Add server/proxy and plugin version fields and mark bungeecord and spigot as discontinued 2026-09-22 18:06:04 +02:00
Andre601 53a1c55634 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.12.0' (#627) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/627
2026-09-19 15:40:36 +02:00
Andre601's Bot c5588f6981 Update dependency com.viaversion:viaversion-api to v5.12.0 2026-09-19 12:03:47 +00:00
Andre601 bac9c7e0f4 Merge pull request 'Update all non-major dependencies to v2.0.1' (#625) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/625
2026-09-17 14:05:59 +02:00
Andre601's Bot f6c3f0f590 Update all non-major dependencies to v2.0.1 2026-09-17 12:05:22 +00:00
Andre601 31f66caef7 Merge pull request 'Update dependency com.velocitypowered:velocity-api to v4.2.0' (#624) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/624
2026-09-15 14:12:27 +02:00
Andre601's Bot f4c9fae031 Update dependency com.velocitypowered:velocity-api to v4.2.0 2026-09-15 12:05:23 +00:00
Andre601 9e212fa2ea Fix unclosed bold tag in announce header. 2026-09-11 01:35:01 +02:00
Andre601 3a25d6185c Merge pull request 'Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.16.0' (#623) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/623
2026-09-03 15:09:17 +02:00
Andre601's Bot 5cf4887ae8 Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.16.0 2026-09-03 12:06:06 +00:00
Andre601 e9bb64affa Merge pull request 'Update dependency com.velocitypowered:velocity-api to v4.1.1' (#622) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/622
2026-08-27 14:10:55 +02:00
Andre601's Bot df34843b7f Update dependency com.velocitypowered:velocity-api to v4.1.1 2026-08-27 12:05:54 +00:00
Andre601 ee5b7d022a Merge pull request 'Update dependency com.velocitypowered:velocity-api to v4.1.0' (#621) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/621
2026-08-25 14:27:38 +02:00
Andre601's Bot 94fbcaa5f4 Update dependency com.velocitypowered:velocity-api to v4.1.0 2026-08-25 12:04:52 +00:00
Andre601 850becd183 Merge pull request 'Update dependency com.google.guava:guava to v33.7.1-jre' (#620) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/620
2026-08-18 14:34:05 +02:00
Andre601's Bot 2a488248af Update dependency com.google.guava:guava to v33.7.1-jre 2026-08-18 12:07:27 +00:00
Andre601 2e78b59c54 Remove duplicate "thank you". 2026-08-17 18:13:09 +02:00
Andre601 4919caefec Merge branch 'master' of https://codeberg.org/Andre601/AdvancedServerList 2026-08-17 18:03:42 +02:00
Andre601 158cac6bbc Merge pull request 'Update dependency com.squareup.okhttp3:okhttp-jvm to v5.5.0' (#619) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/619
2026-08-17 14:24:02 +02:00
Andre601's Bot babbadb495 Update dependency com.squareup.okhttp3:okhttp-jvm to v5.5.0 2026-08-17 12:04:50 +00:00
Andre601 772e25f9f9 Update banner 2026-08-16 18:06:13 +02:00
Andre601 f649c18e51 Use !== for downloads check 2026-08-15 23:58:03 +02:00
Andre601 6cdadae7b4 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.6.3' (#618) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/618
2026-08-14 14:41:25 +02:00
Andre601's Bot c36cb3b9ae Update dependency ch.qos.logback:logback-classic to v1.6.3 2026-08-14 12:04:11 +00:00
Andre601 1776de1ec0 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.6.2' (#617) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/617
2026-08-12 14:10:05 +02:00
Andre601's Bot 0ae7f0990f Update dependency ch.qos.logback:logback-classic to v1.6.2 2026-08-12 12:04:59 +00:00
Andre601 53c4d738af Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.4' (#616) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/616
2026-08-09 14:41:50 +02:00
Andre601's Bot 97d6b9cf2f Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.4 2026-08-09 12:06:37 +00:00
Andre601 cd390ad95e Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.3' (#615) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/615
2026-08-01 15:05:05 +02:00
Andre601's Bot 5a204b2650 Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.3 2026-08-01 12:03:34 +00:00
Andre601 ffce2c7b8d Merge pull request 'Update dependency org.jspecify:jspecify to v1.0.1' (#614) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/614
2026-07-30 14:18:00 +02:00
Andre601's Bot 1fb5eabcad Update dependency org.jspecify:jspecify to v1.0.1 2026-07-30 12:02:51 +00:00
Andre601 7c53ea19e0 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.6.1' (#613) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/613
2026-07-28 14:28:24 +02:00
Andre601's Bot a614d1f2aa Update dependency ch.qos.logback:logback-classic to v1.6.1 2026-07-28 12:05:54 +00:00
Andre601 417303e804 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.6.0' (#612) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/612
2026-07-24 14:12:14 +02:00
Andre601's Bot 9956b02736 Update dependency ch.qos.logback:logback-classic to v1.6.0 2026-07-24 12:03:51 +00:00
Andre601 43b3ddf81c Merge pull request 'Update dependency org.apache.maven.plugins:maven-jar-plugin to v3.5.1' (#611) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/611
2026-07-23 14:17:35 +02:00
Andre601's Bot f0a0c43351 Update dependency org.apache.maven.plugins:maven-jar-plugin to v3.5.1 2026-07-23 12:06:24 +00:00
Andre601 734c124a65 Merge pull request 'Update https://code.forgejo.org/actions/setup-python action to v7' (#610) from renovate/https-code.forgejo.org-actions-setup-python-7.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/610
2026-07-21 14:23:31 +02:00
Andre601 741324d1c7 Merge pull request 'Update all non-major dependencies' (#609) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/609
2026-07-21 14:12:04 +02:00
Andre601's Bot b28ef832c8 Update https://code.forgejo.org/actions/setup-python action to v7 2026-07-21 12:05:08 +00:00
Andre601's Bot 2b1a5aa45b Update all non-major dependencies 2026-07-21 12:04:06 +00:00
Andre601 c9581fe79c Merge pull request 'Update dependency mkdocs-material to v9.7.7' (#608) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/608
2026-07-18 15:41:19 +02:00
Andre601's Bot d385b68d2c Update dependency mkdocs-material to v9.7.7 2026-07-18 12:04:18 +00:00
Andre601 dd82892d39 Merge pull request 'Update dependency com.velocitypowered:velocity-api to v4' (#607) from renovate/com.velocitypowered-velocity-api-4.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/607
2026-07-15 14:13:08 +02:00
Andre601's Bot 32239db674 Update dependency com.velocitypowered:velocity-api to v4 2026-07-15 12:04:42 +00:00
Andre601 16ece42116 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.11.0' (#606) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/606
2026-07-13 14:22:07 +02:00
Andre601's Bot 137cf6e8da Update dependency com.viaversion:viaversion-api to v5.11.0 2026-07-13 12:04:45 +00:00
Andre601 0ba3047acc Merge pull request 'Update dependency com.velocitypowered:velocity-api to v3.5.1' (#605) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/605
2026-07-12 14:04:43 +02:00
Andre601's Bot de7d0ed3ca Update dependency com.velocitypowered:velocity-api to v3.5.1 2026-07-12 12:03:45 +00:00
Andre601 7c6bb28d39 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.38' (#604) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/604
2026-07-09 14:15:28 +02:00
Andre601's Bot 0ce9ec0239 Update dependency ch.qos.logback:logback-classic to v1.5.38 2026-07-09 12:03:11 +00:00
Andre601 1aa196c3d5 Remove bungeecord from getting-started 2026-07-06 18:26:40 +02:00
Andre601 5c7366198e Merge pull request 'Update dependency space.arim.libertybans:bans-api to v1.1.4' (#603) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/603
2026-07-05 14:14:49 +02:00
Andre601's Bot cf7fe7236e Update dependency space.arim.libertybans:bans-api to v1.1.4 2026-07-05 12:03:12 +00:00
Andre601 e69c94da06 Fix wrong VersionUplaoder command 2026-07-03 18:13:53 +02:00
Andre601 7cd3835785 Update SECURITY.md and versions in uploader 2026-07-03 17:56:31 +02:00
Andre601 8c36d27360 Version 5.9.0 2026-07-03 17:47:17 +02:00
Andre601 5329ed1b88 Merge pull request 'Update dependency me.clip:placeholderapi to v2.12.3' (#602) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/602
2026-07-03 14:32:32 +02:00
Andre601's Bot d66494f4dd Update dependency me.clip:placeholderapi to v2.12.3 2026-07-03 12:02:25 +00:00
Andre601 d03ebf5fb1 Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.2' (#601) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/601
2026-06-30 14:22:34 +02:00
Andre601's Bot c7ae2c130f Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.2 2026-06-30 12:03:47 +00:00
Andre601 017a1893c4 Merge pull request 'Update all non-major dependencies to v2.0.0-beta.17' (#600) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/600
2026-06-29 14:09:50 +02:00
Andre601's Bot 7a3af4cb26 Update all non-major dependencies to v2.0.0-beta.17 2026-06-29 12:04:34 +00:00
Andre601 0d05f2fe1d Merge pull request 'Update all non-major dependencies' (#599) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/599
2026-06-27 15:27:15 +02:00
Andre601's Bot 0acb097439 Update all non-major dependencies 2026-06-27 12:04:09 +00:00
Andre601 8a67fbead8 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.36' (#598) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/598
2026-06-26 14:26:16 +02:00
Andre601's Bot 8f3252d66a Update dependency ch.qos.logback:logback-classic to v1.5.36 2026-06-26 12:04:11 +00:00
Andre601 7668a680c4 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.35' (#597) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/597
2026-06-23 14:10:30 +02:00
Andre601's Bot 944e5a7262 Update dependency ch.qos.logback:logback-classic to v1.5.35 2026-06-23 12:05:36 +00:00
Andre601 d7cefb77ce Add target and rel to link 2026-06-22 00:50:43 +02:00
Andre601 e7a44711c0 Use v3 of Modrinth API 2026-06-22 00:47:12 +02:00
Andre601 96750ec5fd Merge pull request 'Update all non-major dependencies' (#594) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/594
2026-06-21 13:15:55 +02:00
Andre601's Bot 16500f29e4 Update all non-major dependencies 2026-06-20 14:14:12 +00:00
Andre601 25e433d0ed Display downloads remaining for 100k 2026-06-20 01:09:55 +02:00
Andre601 21430e9a4e Use codeberg-small for longer runtime 2026-06-19 16:42:27 +02:00
Andre601 de5455ab39 Merge pull request 'Update https://code.forgejo.org/actions/checkout action to v7' (#593) from renovate/https-code.forgejo.org-actions-checkout-7.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/593
2026-06-19 15:26:46 +02:00
Andre601 a52ca1d8be .forgejo/workflows/pr_preview.yml aktualisiert 2026-06-19 15:26:40 +02:00
Andre601 34d8048dd4 Merge pull request 'Update all non-major dependencies to v2.0.0-beta.16' (#592) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/592
2026-06-19 14:12:18 +02:00
Andre601's Bot 3b1e676888 Update https://code.forgejo.org/actions/checkout action to v7 2026-06-19 12:06:42 +00:00
Andre601's Bot 9332a3e342 Update all non-major dependencies to v2.0.0-beta.16 2026-06-19 12:06:33 +00:00
Andre601 eacf227650 Merge pull request 'Update all non-major dependencies to v1.1.3' (#591) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/591
2026-06-16 14:45:50 +02:00
Andre601's Bot 56131f4478 Update all non-major dependencies to v1.1.3 2026-06-16 12:02:51 +00:00
Andre601 b362c34141 Use DefaultExpressionParserEngine 2026-06-09 21:55:46 +02:00
Andre601 41718611e7 Merge pull request 'Update all non-major dependencies to v5.4.0' (#590) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/590
2026-06-09 14:13:18 +02:00
Andre601's Bot a92d6716e4 Update all non-major dependencies to v5.4.0 2026-06-09 12:04:50 +00:00
Andre601 768509100d Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.34' (#588) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/588
2026-06-01 14:17:51 +02:00
Andre601's Bot a64ad0cfa0 Update dependency ch.qos.logback:logback-classic to v1.5.34 2026-06-01 12:04:07 +00:00
Andre601 2abde6ef63 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.33' (#587) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/587
2026-05-28 14:27:41 +02:00
Andre601's Bot da2cf4d501 Update dependency ch.qos.logback:logback-classic to v1.5.33 2026-05-28 12:04:02 +00:00
Andre601 2a00634ce2 Merge pull request 'Update maven Docker tag to v3.9.16' (#586) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/586
2026-05-19 14:04:23 +02:00
Andre601's Bot 58108a8b19 Update maven Docker tag to v3.9.16 2026-05-19 12:03:28 +00:00
Andre601 6e7260d8f2 Bump adventure to 5.1.1 to avoid dependency errors 2026-05-12 17:59:48 +02:00
Andre601 d75f43a4bd Merge pull request 'Update all non-major dependencies to v5.1.0' (#585) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/585
2026-05-12 17:56:09 +02:00
Andre601's Bot 442c1539e9 Update all non-major dependencies to v5.1.0 2026-05-12 12:02:57 +00:00
Andre601 a6188905dc Merge pull request 'andre601-patch-1' (#584) from andre601-patch-1 into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/584
2026-05-07 11:05:09 +02:00
Andre601 81e0778825 Use version range 2026-05-07 11:03:27 +02:00
Andre601 afdcd11f7c Use version range 2026-05-07 11:02:46 +02:00
Andre601 4ca00cd8ad Merge pull request 'Update all non-major dependencies' (#583) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/583
2026-05-06 15:01:59 +02:00
Andre601's Bot 3b2d6b98b2 Update all non-major dependencies 2026-05-05 12:06:22 +00:00
Andre601 348d1fcacf v5.8.0
- Use 1.7.0-b1 of ExpressionParser
- Wrap condition evaluation in try-catch to prevent stacktrace spams for invalid protocols (bots?) pinging.
2026-05-03 21:39:48 +02:00
Andre601 4451d2382b Remove FakePlayerProfile and make hover only work on newer Paper versions 2026-05-01 21:53:52 +02:00
Andre601 3d410631ef Merge pull request 'Update dependency io.papermc.paper:paper-api to v26' (#582) from renovate/io.papermc.paper-paper-api-26.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/582
2026-05-01 14:07:15 +02:00
Andre601 e0ba710aed paper/pom.xml aktualisiert 2026-05-01 14:07:06 +02:00
Andre601's Bot 966d817f29 Update dependency io.papermc.paper:paper-api to v26 2026-05-01 12:05:19 +00:00
Andre601 838416b1c5 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.14.4' (#581) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/581
2026-04-29 14:17:44 +02:00
Andre601's Bot 23ee4a08ad Update dependency org.junit.jupiter:junit-jupiter-engine to v5.14.4 2026-04-29 12:04:12 +00:00
Andre601 baba7c7076 Use git-pages action for docs deployment 2026-04-25 14:14:23 +02:00
Andre601 7e7228dd77 Merge pull request 'Update dependency com.google.code.gson:gson to v2.14.0' (#580) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/580
2026-04-25 14:09:40 +02:00
Andre601's Bot 103bf4f1db Update dependency com.google.code.gson:gson to v2.14.0 2026-04-25 12:04:19 +00:00
Andre601 0c7c8e56db Update default config in getting-started.md 2026-04-25 01:25:17 +02:00
Andre601 cb3161a118 Merge pull request 'Update dependency net.kyori:adventure-text-serializer-legacy to v5' (#579) from renovate/major-dependency.adventure-text-serializer-legacy into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/579
2026-04-22 14:11:44 +02:00
Andre601 326fe7098a Merge pull request 'Update all non-major dependencies' (#578) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/578
2026-04-22 14:11:25 +02:00
Andre601's Bot d79c54f7c9 Update dependency net.kyori:adventure-text-serializer-legacy to v5 2026-04-22 12:04:30 +00:00
Andre601's Bot 1468febf72 Update all non-major dependencies 2026-04-22 12:04:25 +00:00
Andre601 afbcad6c3e Merge pull request 'Update dependency net.kyori:adventure-text-minimessage to v5' (#577) from renovate/major-dependency.adventure-text-minimessage into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/577
2026-04-19 14:06:31 +02:00
Andre601 79aefaa6a5 Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.1' (#576) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/576
2026-04-19 14:06:06 +02:00
Andre601's Bot d6ac483a0e Update dependency net.kyori:adventure-text-minimessage to v5 2026-04-19 12:05:15 +00:00
Andre601's Bot 35df0d84ca Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.1 2026-04-19 12:04:58 +00:00
Andre601 45229bd6d2 Merge pull request 'Update dependency eu.kennytv.maintenance:maintenance-api to v5' (#575) from renovate/eu.kennytv.maintenance-maintenance-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/575
2026-04-18 14:14:07 +02:00
Andre601 7bfa88383d Merge pull request 'Update dependency net.kyori:adventure-api to v5.0.1' (#574) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/574
2026-04-18 14:12:28 +02:00
Andre601's Bot efaae58562 Update dependency eu.kennytv.maintenance:maintenance-api to v5 2026-04-18 12:07:08 +00:00
Andre601's Bot 7dfdbb621d Update dependency net.kyori:adventure-api to v5.0.1 2026-04-18 12:06:54 +00:00
Andre601 d2cd554fb1 Merge pull request 'Update dependency net.kyori:adventure-api to v5' (#573) from renovate/major-dependency.adventure-api into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/573
2026-04-16 15:50:12 +02:00
Andre601 69168efb01 Merge pull request 'Update dependency com.google.guava:guava to v33.6.0-jre' (#572) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/572
2026-04-16 15:49:56 +02:00
Andre601's Bot 55f94a8c27 Update dependency net.kyori:adventure-api to v5 2026-04-16 12:04:32 +00:00
Andre601's Bot e813bdaba4 Update dependency com.google.guava:guava to v33.6.0-jre 2026-04-16 12:04:13 +00:00
Andre601 b3f56aa398 Merge pull request 'Update all non-major dependencies to v2.0.0-beta.15' (#571) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/571
2026-04-12 14:43:39 +02:00
Andre601's Bot 87f0573162 Update all non-major dependencies to v2.0.0-beta.15 2026-04-12 12:04:33 +00:00
Andre601 e49fe391d0 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.8.1' (#570) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/570
2026-03-31 14:06:26 +02:00
Andre601's Bot d077efdc12 Update dependency com.viaversion:viaversion-api to v5.8.1 2026-03-31 12:04:41 +00:00
Andre601 90fdaf628c Merge pull request 'Update dependency mkdocs-redirects to v1.2.3' (#569) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/569
2026-03-29 14:17:30 +02:00
Andre601's Bot 9651011b19 Update dependency mkdocs-redirects to v1.2.3 2026-03-29 12:02:58 +00:00
Andre601 9bacc04a68 Compile with Java 25 2026-03-28 13:52:41 +01:00
Andre601 515081e395 Merge pull request 'Update all non-major dependencies' (#568) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/568
2026-03-28 13:07:37 +01:00
Andre601's Bot 95fec87c12 Update all non-major dependencies 2026-03-28 12:07:06 +00:00
Andre601 778a415b4f Merge pull request 'Update dependency properdocs to v1.6.7' (#567) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/567
2026-03-21 14:23:28 +01:00
Andre601's Bot db66945d99 Update dependency properdocs to v1.6.7 2026-03-21 12:02:41 +00:00
67 changed files with 1072 additions and 2950 deletions

No files matched your search

+10 -16
View File
@@ -15,29 +15,23 @@ on:
jobs:
deployWiki:
runs-on: codeberg-tiny
runs-on: codeberg-small
steps:
- name: "Checkout Source Repository"
uses: https://code.forgejo.org/actions/checkout@v6
- name: "Checkout Repository"
uses: https://code.forgejo.org/actions/checkout@v7
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@v6
uses: https://code.forgejo.org/actions/setup-python@v7
with:
python-version: 3.x
- name: "Install Dependencies"
run: "pip install -r requirements.txt"
- name: "Build Website"
run: "properdocs 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
- name: "Deploy Website"
uses: https://code.forgejo.org/actions/git-pages@v2
with:
site: https://asl.andre601.ch
token: ${{ secrets.FORGEJO_TOKEN }}
source: site/
+3 -3
View File
@@ -20,7 +20,7 @@ env:
jobs:
createPreview:
runs-on: codeberg-tiny
runs-on: codeberg-small
steps:
#
# Finding and updating comment in Pull request.
@@ -49,7 +49,7 @@ jobs:
# Build website and push.
#
- name: "Checkout Source Repository"
uses: https://code.forgejo.org/actions/checkout@v6
uses: https://code.forgejo.org/actions/checkout@v7
with:
token: ${{ secrets.BOT_TOKEN }}
fetch-depth: 0
@@ -60,7 +60,7 @@ jobs:
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@v6
uses: https://code.forgejo.org/actions/setup-python@v7
with:
python-version: 3.x
- name: "Install Dependencies"
+35 -5
View File
@@ -16,13 +16,14 @@ body:
label: Platform
description: On what platform do you use the plugin?
options:
- BungeeCord
- Other (Please specify)
- Paper
- Purpur
- Spigot
- Folia
- Velocity
- Waterfall
- Other (Please specify)
- Spigot (DISCONTINUED)
- BungeeCord (DISCONTINUED)
- Waterfall (DISCONTINUED)
validations:
required: true
- type: input
@@ -32,6 +33,35 @@ body:
Please provide the name of the platform (Proxy/Server) you use, if you selected `Other (Please specify)` in the above section.
Leave empty otherwise.
placeholder: SomeProxy
- type: input
attributes:
label: Server/Proxy version
description: |-
Provide the Version of your Server/Proxy.
For Paper and its forks, run `/version` and for Velocity run `/velocity info`
placeholder: This server is running Paper version ...
validations:
required: true
- type: input
attributes:
label: Plugin version
description: |-
Provide the Version of the Plugin.
On Paper and its forks, run `/version AdvancedServerList` and on Velocity, run `/velocity plugins` and find the AdvancedServerList entry.
placeholder: 5.9.0
validations:
required: true
- type: input
attributes:
label: Logs
description: |-
Provide Logs from your Server/Proxy, uploaded to [mclo.gs](https://mclo.gs).
**DO NOT SKIP THIS!**
Skipping this by writing "Not needed", "private", etc. will get your issue closed without warning!
placeholder: 'https://mclo.gs/...'
validations:
required: true
- type: textarea
attributes:
label: What happened?
@@ -49,7 +79,7 @@ body:
placeholder: |-
1. Do this
2. ...
3. Profit!
3. Prof-... Bug!
validations:
required: true
- type: textarea
-64
View File
@@ -1,64 +0,0 @@
when:
- event: pull_request
path:
include: [".woodpecker/pr_preview.yml", "docs/**", "mkdocs.yml", "requirements.txt"]
variables:
setup_git: &setup_git
- apk add git
- git config --global user.email "andre_601-bot@noreply.codeberg.org"
- git config --global user.name "PR Docs Preview Builder"
steps:
- name: "Clone Preview Repository"
image: alpine:3.20.3
commands:
- chmod -R a+w .
- <<: *setup_git
- git clone https://codeberg.org/Andre601/preview.git site
- chmod -R a+w site
- cd site
- git switch ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST} 2>/dev/null || git switch -c ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST}
- name: "Build Docs"
image: woodpeckerci/plugin-mkdocs:latest
settings:
pip_install_file: requirements.txt
- name: "Commit and Push"
image: alpine:3.20.3
secrets:
- bot_token
commands:
- <<: *setup_git
- mv preview-domains site/.domains
- cd site
- git remote add upstream https://$BOT_TOKEN@codeberg.org/Andre601/preview.git
- git add --all
- git commit -m "Update Preview for ${CI_REPO_NAME}/${CI_COMMIT_PULL_REQUEST} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
- git push --set-upstream upstream ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST} -f
- name: "Comment on Success"
image: mcs94/gitea-comment
when:
- status: ["success"]
settings:
gitea_address: https://codeberg.org
gitea_token:
from_secret: BOT_TOKEN
comment: |-
Pull request Preview Ready!
| Name | Value |
|--------|--------------------------------------------------------------------------|
| Commit | ${CI_COMMIT_SHA} |
| Link | https://preview.andre601.ch/@${CI_REPO_NAME,,}~${CI_COMMIT_PULL_REQUEST} |
- name: "Comment on Failure"
image: mcs94/gitea-comment
when:
- status: ["failure"]
settings:
gitea_address: https://codeberg.org
gitea_token:
from_secret: BOT_TOKEN
comment: |-
Pull request Preview **failed**!
Please check the CI logs for details: ${CI_PIPELINE_URL}
+2 -3
View File
@@ -4,7 +4,7 @@ when:
steps:
- name: "Build Jar and Upload"
image: maven:3.9.14-eclipse-temurin-21
image: maven:3.9.16-eclipse-temurin-25
environment:
CODEBERG_API_TOKEN:
from_secret: cb_token
@@ -19,13 +19,12 @@ steps:
- cd version-uploader/target
- mv VersionUploader.jar ../../
- cd ../../
- java -jar VersionUploader.jar --all
- java -jar VersionUploader.jar upload all
- name: "Upload Jars to Codeberg"
image: woodpeckerci/plugin-gitea-release
settings:
base_url: https://codeberg.org
files:
- "bungeecord/target/AdvancedServerList-*.jar"
- "paper/target/AdvancedServerList-*.jar"
- "velocity/target/AdvancedServerList-*.jar"
- "addons/banplugins/target/AdvancedServerList-*.jar"
-36
View File
@@ -1,36 +0,0 @@
when:
- event: push
branch: ${CI_REPO_DEFAULT_BRANCH}
path:
include: [".woodpecker/publish_docs.yml", "docs/**", "mkdocs.yml", "requirements.txt"]
variables:
setup_git: &setup_git
- apk add git
- git config --global user.email "andre_601-bot@noreply.codeberg.org"
- git config --global user.name "ASL Docs Builder"
steps:
- name: "Clone target Repository"
image: alpine:3.20.3
commands:
- chmod -R a+w .
- <<: *setup_git
- git clone -b pages https://codeberg.org/Andre601/asl-docs.git site
- chmod -R a+w site
- name: "Build Docs"
image: woodpeckerci/plugin-mkdocs:latest
settings:
pip_install_file: requirements.txt
- name: "Commit and Push"
image: alpine:3.20.3
secrets:
- bot_token
commands:
- <<: *setup_git
- mv domains site/.domains
- cd site
- git remote set-url origin https://$BOT_TOKEN@codeberg.org/Andre601/asl-docs.git
- git add --all
- git commit -m "Update AdvancedServerList Docs ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
- git push
+5 -5
View File
@@ -19,6 +19,8 @@ To ensure proper safety and support are only certain versions and Platforms of A
| Server/Proxy Version* | Supported |
|-----------------------|-----------|
| 26.2 | Yes |
| 26.1.x | Yes |
| 1.21.x | Yes |
| 1.20.x | Yes |
| 1.19.x | No |
@@ -53,8 +55,6 @@ To ensure proper safety and support are only certain versions and Platforms of A
| 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.
| BungeeCord | No |
| Waterfall | No |
| Velocity | Yes |
+3 -17
View File
@@ -62,30 +62,16 @@
<dependencies>
<!-- Proxy/Server -->
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.21-R0.4</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.21-R0.4</version>
<type>javadoc</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<version>[26.1.2.build,)</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>3.4.0</version>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
@@ -99,7 +85,7 @@
<dependency>
<groupId>space.arim.libertybans</groupId>
<artifactId>bans-api</artifactId>
<version>1.1.2</version>
<version>1.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,68 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.banplugins.bungeecord;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
import net.md_5.bungee.api.plugin.Plugin;
public class BungeeCordBanPluginsAddon extends Plugin{
@Override
public void onEnable(){
if(getProxy().getPluginManager().getPlugin("AdvancedServerList") == null){
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
return;
}
int loadedPlaceholders = loadPlaceholderProviders();
if(loadedPlaceholders == 0){
getLogger().warning("No compatible Ban plugin was found to register placeholders for.");
}else{
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
}
}
private int loadPlaceholderProviders(){
int loaded = 0;
AdvancedServerListAPI api = AdvancedServerListAPI.get();
for(BanPluginsList entry : BanPluginsList.values()){
if(!entry.supportsBungeeCord())
continue;
if(getProxy().getPluginManager().getPlugin(entry.getName()) != null){
getLogger().info("Registering Placeholders for " + entry.getName() + "...");
api.addPlaceholderProvider(entry.getPlaceholderProvider());
getLogger().info("Placeholders successfully registered!");
loaded++;
}
}
return loaded;
}
}
@@ -1,12 +0,0 @@
name: 'ASLBanPluginsAddon'
author: 'Andre_601'
version: '${plugin.version}'
description: 'AdvancedBan Add-on for AdvancedServerList to add placeholders to use.'
softDepends:
- AdvancedServerList
- AdvancedBan
- LibertyBans
- LiteBans
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
+2 -2
View File
@@ -75,13 +75,13 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<version>[26.1.2.build,)</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>3.4.0</version>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
@@ -1,39 +0,0 @@
package ch.andre601.advancedserverlist.luckperms.bungee;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.exceptions.InvalidPlaceholderProviderException;
import ch.andre601.advancedserverlist.luckperms.placeholders.LuckPermsPlaceholder;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.md_5.bungee.api.plugin.Plugin;
public class LuckPermsAddon extends Plugin{
@Override
public void onEnable(){
if(getProxy().getPluginManager().getPlugin("AdvancedServerList") == null){
getLogger().warning("AdvancedServerList not found. This plugin is required.");
return;
}
if(getProxy().getPluginManager().getPlugin("LuckPerms") == null){
getLogger().warning("LuckPerms not found. This plugin is required.");
return;
}
LuckPerms luckPerms;
try{
luckPerms = LuckPermsProvider.get();
}catch(IllegalStateException ex){
getLogger().severe("Unable to obtain LuckPerms API instance! The Plugin won't work.");
return;
}
getLogger().info("Registering LuckPerms Placeholders...");
try{
AdvancedServerListAPI.get().addPlaceholderProvider(new LuckPermsPlaceholder(luckPerms));
getLogger().info("Successfully registered Placeholder!");
}catch(InvalidPlaceholderProviderException ex){
getLogger().warning("Couldn't register Placeholder. The plugin won't work.");
}
}
}
@@ -1,10 +0,0 @@
name: 'ASLLuckPermsAddon'
author: 'Andre_601'
version: '${plugin.version}'
description: 'LuckPerms Add-on for AdvancedServerList to add placeholders to use.'
softDepends:
- AdvancedServerList
- LuckPerms
main: 'ch.andre601.advancedserverlist.luckperms.bungee.LuckPermsAddon'
-220
View File
@@ -1,220 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>ch.andre601.advancedserverlist</groupId>
<version>parent</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bungeecord</artifactId>
<packaging>jar</packaging>
<version>${plugin.version}</version>
<description>${plugin.description}</description>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository>
<id>repo-sayandevelopment</id>
<url>https://repo.sayandev.org/releases/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>ch.andre601.advancedserverlist</groupId>
<artifactId>core</artifactId>
<version>${plugin.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>platform-bungeecord</artifactId>
<version>${api.version}</version>
<scope>compile</scope>
</dependency>
<!-- BungeeCord API -->
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<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.21-R0.3</version>
<type>javadoc</type>
<scope>provided</scope>
</dependency>
<!-- Adventure Library -->
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>${dependency.adventure-api}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>${dependency.adventure-text-minimessage}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bungeecord</artifactId>
<version>${dependency.adventure-platform-bungeecord}</version>
<scope>provided</scope>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bungeecord</artifactId>
<version>3.2.1</version>
<scope>compile</scope>
</dependency>
<!-- Configurate -->
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<version>${dependency.configurate-yaml}</version>
<scope>provided</scope>
</dependency>
<!-- Plugins -->
<dependency>
<groupId>com.github.LeonMangler</groupId>
<artifactId>PremiumVanishAPI</artifactId>
<version>2.9.18-2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-api</artifactId>
<version>1.7.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-proxy-bungeecord</artifactId>
<version>1.7.3</version>
<scope>provided</scope>
</dependency>
<!-- Other -->
<dependency>
<groupId>com.alessiodp.libby</groupId>
<artifactId>libby-bungee</artifactId>
<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}${project.build.build_id}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</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>
</plugins>
</build>
</project>
@@ -1,276 +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.bungeecord;
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.interfaces.dialogs.IDialog;
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
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 BungeeCommandManagerInterface handler;
private BungeeLibraryManager libraryManager = null;
@Override
public void onLoad(){
// 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){
getLogger().info("Library loading completed successfully!");
}else{
getLogger().warning("Library loading completed with errors!");
}
}
@Override
public void onEnable(){
if(!successfulLoad){
logger.warn("There were issues during the plugins Loading-phase! Please see the console for possible reasons.");
logger.warn("Aborting further enabling of the plugin to avoid errors.");
return;
}
this.audiences = BungeeAudiences.create(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();
getProxy().getScheduler().cancel(this);
audiences.close();
}
@Override
public void loadEvents(){
new PlayerJoinEventListener(this);
new ProxyPingEventListener(this);
}
@Override
public void loadMetrics(){
new Metrics(this, 15585).addCustomChart(new SimplePie("profiles",
() -> String.valueOf(core.fileHandler().profiles().size())
));
}
@Override
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
faviconHandler = new FaviconHandler<>(core);
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
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> core(){
return core;
}
@Override
public Path folderPath(){
return getDataFolder().toPath();
}
@Override
public PluginLogger pluginLogger(){
return logger;
}
@Override
public FaviconHandler<Favicon> faviconHandler(){
if(faviconHandler == null)
faviconHandler = new FaviconHandler<>(core);
return faviconHandler;
}
@Override
public CommandManager<CmdSender> commandManager(){
return handler.commandHandler();
}
@Override
public String platformInfo(){
return getProxy().getName() + " " + getProxy().getVersion();
}
@Override
public String loader(){
return "bungeecord";
}
@Override
public boolean isPluginEnabled(String plugin){
return getProxy().getPluginManager().getPlugin(plugin) != null;
}
@Override
public boolean isDialogsSupported(){
return false;
}
@Override
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
return Favicon.create(image);
}
@Override
public IDialogList.IDialogListBuilder createDialogListBuilder(String title){
return null;
}
@Override
public IDialog.IDialogBuilder createDialogBuilder(String title, ServerListProfile profile, int profilesPosition){
return null;
}
public BungeeAudiences audiences(){
return audiences;
}
public int onlinePlayers(ServerInfo server){
List<ProxiedPlayer> players = new ArrayList<>(server == null ? getProxy().getPlayers() : server.getPlayers());
// 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> fetchedServers(){
return fetchedServers;
}
private boolean loadLibs(){
try{
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){
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);
}));
}
}
@@ -1,63 +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.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{
private final CommandSender sender;
private final BungeeAudiences bungeeAudiences;
public BungeeCmdSender(CommandSender sender, BungeeAudiences bungeeAudiences){
this.sender = sender;
this.bungeeAudiences = bungeeAudiences;
}
@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,60 +0,0 @@
/*
* 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.bungeecord.commands;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandManagerInterface;
import net.md_5.bungee.api.CommandSender;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.SenderMapper;
import org.incendo.cloud.bungee.BungeeCommandManager;
import org.incendo.cloud.execution.ExecutionCoordinator;
public class BungeeCommandManagerInterface implements CommandManagerInterface<CommandSender>{
private final BungeeCordCore plugin;
public BungeeCommandManagerInterface(BungeeCordCore plugin){
this.plugin = plugin;
}
@Override
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.audiences()),
sender -> ((BungeeCmdSender)sender).sender()
);
}
}
@@ -1,219 +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.bungeecord.listeners;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeePlayerImpl;
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeeProxyImpl;
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;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ProxyPingEvent;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePlayerImpl>{
private final BungeeCordCore plugin;
private final ProxyPingEvent event;
private final ServerPing.Protocol protocol;
private final ServerPing ping;
public BungeeEventWrapper(BungeeCordCore plugin, ProxyPingEvent event){
this.plugin = plugin;
this.event = event;
this.protocol = event.getResponse().getVersion();
this.ping = event.getResponse();
}
@Override
public GenericServerListEvent callEvent(ProfileEntry entry){
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
plugin.getProxy().getPluginManager().callEvent(event);
return event;
}
@Override
public void maxPlayers(int maxPlayers){
ping.getPlayers().setMax(maxPlayers);
}
@Override
public void onlinePlayers(int onlinePlayers){
ping.getPlayers().setOnline(onlinePlayers);
}
@Override
public void motd(Component component){
ping.setDescriptionComponent(new TextComponent(BungeeComponentSerializer.get().serialize(component)));
}
@Override
public void hidePlayers(){
ping.setPlayers(null);
}
@Override
public void playerCount(String name){
protocol.setName(name);
protocol.setProtocol(-1);
}
@Override
public void players(List<String> lines, BungeePlayerImpl player, GenericServer server){
ServerPing.PlayerInfo[] players = new ServerPing.PlayerInfo[lines.size()];
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());
players[i] = pi;
}
if(players.length > 0)
ping.getPlayers().setSample(players);
}
@Override
public void playersHidden(){
ping.getPlayers().setSample(new ServerPing.PlayerInfo[0]);
}
@Override
public void favicon(Favicon favicon){
ping.setFavicon(favicon);
}
@Override
public void defaultFavicon(){
ping.setFavicon(ping.getFaviconObject());
}
@Override
public void updateEvent(){
this.ping.setVersion(this.protocol);
this.event.setResponse(this.ping);
}
@Override
public boolean isInvalidProtocol(){
return protocol == null;
}
@Override
public boolean isMaintenanceModeActive(){
if(plugin.getProxy().getPluginManager().getPlugin("Maintenance") == null)
return false;
return MaintenanceUtil.get().isMaintenanceEnabled();
}
@Override
public int protocolVersion(){
return event.getConnection().getVersion();
}
@Override
public int onlinePlayers(){
return plugin.onlinePlayers(null);
}
@Override
public int maxPlayers(){
return ping.getPlayers().getMax();
}
@Override
public String playerIP(){
return ((InetSocketAddress)event.getConnection().getSocketAddress()).getHostString();
}
@Override
public String parsePAPIPlaceholders(String text, BungeePlayerImpl player){
if(plugin.getProxy().getPluginManager().getPlugin("PAPIProxyBridge") == null)
return text;
if(!PAPIUtil.get().isCompatible())
return text;
String server = PAPIUtil.get().getServer();
if(server == null || server.isEmpty())
return text;
ServerInfo serverInfo = plugin.getProxy().getServerInfo(server);
if(serverInfo == null || serverInfo.getPlayers().isEmpty())
return text;
ProxiedPlayer carrier = PAPIUtil.get().getPlayer(serverInfo.getPlayers());
if(carrier == null)
return text;
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
}
@Override
public String virtualHost(){
return this.resolveHost(event.getConnection().getVirtualHost());
}
@Override
public PluginCore<Favicon> plugin(){
return plugin;
}
@Override
public BungeePlayerImpl createPlayer(CachedPlayer player, int protocol){
return new BungeePlayerImpl(player, protocol);
}
@Override
public GenericServer createServer(int playersOnline, int playersMax, String host){
Map<String, ServerInfo> servers = plugin.getProxy().getServers();
return new BungeeProxyImpl(servers, playersOnline, playersMax, host);
}
}
@@ -1,61 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord.listeners;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.commands.BungeeCmdSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.net.InetSocketAddress;
public class PlayerJoinEventListener implements Listener{
private final BungeeCordCore plugin;
public PlayerJoinEventListener(BungeeCordCore plugin){
this.plugin = plugin;
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@EventHandler
public void onJoin(PostLoginEvent event){
InetSocketAddress address = (InetSocketAddress)event.getPlayer().getPendingConnection().getSocketAddress();
ProxiedPlayer player = event.getPlayer();
plugin.core().playerHandler().addPlayer(address.getHostString(), player.getName(), player.getUniqueId());
if(player.hasPermission("advancedserverlist.admin") || player.hasPermission("advancedserverlist.updatecheck")){
if(plugin.audiences() == null || plugin.core().updateChecker() == null)
return;
BungeeCmdSender sender = new BungeeCmdSender(player, plugin.audiences());
plugin.core().updateChecker().performCachedUpdateCheck(sender);
}
}
}
@@ -1,36 +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.bungeecord.listeners;
import ch.andre601.advancedserverlist.api.bungeecord.events.PreServerListSetEvent;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
public class PreServerListSetEventImpl extends PreServerListSetEvent{
public PreServerListSetEventImpl(ProfileEntry entry){
super(entry);
}
}
@@ -1,51 +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.bungeecord.listeners;
import ch.andre601.advancedserverlist.api.bungeecord.events.PostServerListSetEvent;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
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 ProxyPingEventListener implements Listener{
private final BungeeCordCore plugin;
public ProxyPingEventListener(BungeeCordCore plugin){
this.plugin = plugin;
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@EventHandler(priority = 90) // Maintenance has Event Priority 80, so we need to be AFTER it.
public void onProxyPing(ProxyPingEvent event){
ProfileEntry entry = PingEventHandler.handleEvent(new BungeeEventWrapper(plugin, event));
plugin.getProxy().getPluginManager().callEvent(new PostServerListSetEvent(entry));
}
}
@@ -1,76 +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.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;
public class BungeeLogger implements PluginLogger{
private final BungeeCordCore plugin;
private final Logger logger;
public BungeeLogger(BungeeCordCore plugin){
this.plugin = plugin;
this.logger = plugin.getLogger();
}
@Override
public void debug(Class<?> clazz, String msg, Object... args){
if(plugin.isDebugEnabled())
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
}
@Override
public void debugWarn(Class<?> clazz, String msg, Object... args){
if(plugin.isDebugEnabled())
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
}
@Override
public void info(String msg, Object... args){
logger.info(ComponentParser.textFormatted(msg, args).toStringStriped());
}
@Override
public void warn(String msg, Object... args){
logger.warning(ComponentParser.textFormatted(msg, args).toStringStriped());
}
@Override
public void warn(String msg, Throwable throwable){
logger.log(Level.WARNING, ComponentParser.text(msg).toStringStriped(), throwable);
}
@Override
public void warn(String msg, Throwable throwable, Object... args){
logger.log(Level.WARNING, ComponentParser.textFormatted(msg, args).toStringStriped(), throwable);
}
}
@@ -1,51 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord.objects.impl;
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeePlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import org.jspecify.annotations.NullMarked;
import java.util.UUID;
@NullMarked
public record BungeePlayerImpl(CachedPlayer player, int protocol) implements BungeePlayer{
@Override
public String getName(){
return player.name();
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return player.uuid();
}
}
@@ -1,54 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord.objects.impl;
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
import net.md_5.bungee.api.config.ServerInfo;
import org.jspecify.annotations.NonNull;
import java.util.Map;
public record BungeeProxyImpl(Map<String, ServerInfo> servers, int playersOnline, int playersMax, String host) implements BungeeProxy{
@Override
public @NonNull Map<String, ServerInfo> getServers(){
return servers;
}
@Override
public int getPlayersOnline(){
return playersOnline;
}
@Override
public int getPlayersMax(){
return playersMax;
}
@Override
public String getHost(){
return host;
}
}
@@ -1,56 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord.objects.placeholders;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Locale;
@NullMarked
public class BungeePlayerPlaceholders extends PlaceholderProvider{
private BungeePlayerPlaceholders(){
super("player");
}
public static BungeePlayerPlaceholders init(){
return new BungeePlayerPlaceholders();
}
@Override
public @Nullable String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
return switch(placeholder.toLowerCase(Locale.ROOT)){
case "name" -> player.getName();
case "protocol" -> String.valueOf(player.getProtocol());
case "uuid" -> String.valueOf(player.getUUID());
default -> null;
};
}
}
@@ -1,64 +0,0 @@
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;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
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 @Nullable String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
String[] args = placeholder.split("\\s", 2);
if(args.length < 2)
return null;
ServerPing ping = plugin.fetchedServers().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;
};
}
}
@@ -1,106 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord.objects.placeholders;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import net.md_5.bungee.api.config.ServerInfo;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.net.InetSocketAddress;
@NullMarked
public class BungeeServerPlaceholders extends PlaceholderProvider{
private final BungeeCordCore plugin;
private BungeeServerPlaceholders(BungeeCordCore plugin){
super("server");
this.plugin = plugin;
}
public static BungeeServerPlaceholders init(BungeeCordCore plugin){
return new BungeeServerPlaceholders(plugin);
}
@Override
public @Nullable String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
if(!(server instanceof BungeeProxy proxy))
return null;
String[] args = placeholder.split("\\s", 2);
return switch(args[0]){
case "playersOnline" -> {
if(args.length >= 2){
String[] servers = args[1].split(",");
int players = 0;
for(String serverName : servers){
if(serverName.isEmpty())
continue;
ServerInfo info = proxy.getServers().get(serverName.strip());
if(info == null)
continue;
players += plugin.onlinePlayers(info);
}
yield String.valueOf(players);
}
yield String.valueOf(proxy.getPlayersOnline());
}
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 "";
yield String.valueOf(proxy.getPlayersMax());
}
case "host" -> {
if(args.length > 2)
yield "";
if(args.length == 2 && !args[1].isEmpty()){
ServerInfo info = proxy.getServers().get(args[1]);
if(info == null)
yield "";
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
}
yield proxy.getHost();
}
default -> null;
};
}
}
-11
View File
@@ -1,11 +0,0 @@
name: 'AdvancedServerList'
author: 'Andre_601'
version: '${plugin.version}'
description: '${plugin.description}'
softDepends:
- PAPIProxyBridge
- Maintenance
- ServerListPlus
main: 'ch.andre601.advancedserverlist.bungeecord.BungeeCordCore'
@@ -1,28 +0,0 @@
{
"libraries": [
{
"groupId": "net{}kyori",
"artifactId": "adventure-api",
"version": "${dependency.adventure-api}",
"resolveTransitiveDependencies": true
},
{
"groupId": "net{}kyori",
"artifactId": "adventure-text-minimessage",
"version": "${dependency.adventure-text-minimessage}",
"resolveTransitiveDependencies": true
},
{
"groupId": "net{}kyori",
"artifactId": "adventure-platform-bungeecord",
"version": "${dependency.adventure-platform-bungeecord}",
"resolveTransitiveDependencies": true
},
{
"groupId": "org{}spongepowered",
"artifactId": "configurate-yaml",
"version": "${dependency.configurate-yaml}",
"resolveTransitiveDependencies": true
}
]
}
+8 -8
View File
@@ -79,7 +79,7 @@
<dependency>
<groupId>ch.andre601</groupId>
<artifactId>expressionparser</artifactId>
<version>1.6.1</version>
<version>1.7.0-b1</version>
<scope>compile</scope>
</dependency>
@@ -121,7 +121,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.2</version>
<version>2.14.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -133,7 +133,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.5.0-jre</version>
<version>33.7.1-jre</version>
<scope>provided</scope>
</dependency>
@@ -161,7 +161,7 @@
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.0</version>
<version>1.0.1</version>
</dependency>
<!-- Plugins -->
@@ -174,7 +174,7 @@
<dependency>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-api</artifactId>
<version>4.2.1</version>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -186,7 +186,7 @@
<dependency>
<groupId>io.github.miniplaceholders</groupId>
<artifactId>miniplaceholders-api</artifactId>
<version>3.1.0</version>
<version>3.2.0</version>
<scope>provided</scope>
</dependency>
@@ -194,7 +194,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.14.3</version>
<version>5.14.4</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -221,7 +221,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<version>3.16.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
@@ -28,8 +28,7 @@ package ch.andre601.advancedserverlist.core;
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.commands.CommandTypePostprocessor;
import ch.andre601.advancedserverlist.core.commands.*;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenancePlaceholder;
import ch.andre601.advancedserverlist.core.file.FileHandler;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
@@ -38,12 +37,13 @@ import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.TextCenterUtil;
import ch.andre601.advancedserverlist.core.placeholders.DatePlaceholder;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.advancedserverlist.core.profiles.conditions.reader.PlaceholderTokenReader;
import ch.andre601.advancedserverlist.core.profiles.conditions.reader.PlaceholderValueReader;
import ch.andre601.advancedserverlist.core.profiles.handlers.PlayerHandler;
import ch.andre601.expressionparser.DefaultExpressionParserEngine;
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;
@@ -75,7 +75,11 @@ public class AdvancedServerList<F>{
private final TextCenterUtil textCenterUtil;
private static final AdvancedServerListAPI api = AdvancedServerListAPI.get();
private final ProfileConditionParser parser = ProfileConditionParser.create();
private final DefaultExpressionParserEngine parser = new DefaultExpressionParserEngine.DefaultBuilder()
.addDefaults()
.addTokenReader(new PlaceholderTokenReader())
.addValueReader(new PlaceholderValueReader())
.build();
private UpdateChecker updateChecker;
@@ -120,7 +124,7 @@ public class AdvancedServerList<F>{
return version;
}
public ProfileConditionParser parser(){
public DefaultExpressionParserEngine parser(){
return parser;
}
@@ -228,7 +232,6 @@ public class AdvancedServerList<F>{
CommandManager<CmdSender> commandManager = plugin().commandManager();
commandManager.parameterInjectorRegistry().registerInjector(AdvancedServerList.class, ParameterInjector.constantInjector(this));
commandManager.registerCommandPostProcessor(new CommandTypePostprocessor());
AnnotationParser<CmdSender> annotationParser = new AnnotationParser<>(commandManager, CmdSender.class);
@@ -236,9 +239,15 @@ public class AdvancedServerList<F>{
CommandType.class,
(annotation, builder) -> builder.meta(CommandHandler.COMMAND_TYPE, annotation.value())
);
annotationParser.parse(new CommandHandler(commandManager));
annotationParser.parse(
CmdClearCache.create(this),
CmdHelp.create(commandManager),
CmdMigrate.create(this),
CmdProfiles.create(this),
CmdReload.create(this)
);
for(String option : CommandHandler.PROFILE_OPTIONS){
for(String option : CmdProfiles.ProfileOption.list()){
commandManager.command(
commandManager.commandBuilder("advancedserverlist", "asl")
.literal("profiles")
@@ -25,13 +25,13 @@
package ch.andre601.advancedserverlist.core.check;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NonNull;
import java.util.concurrent.ThreadFactory;
public class UpdateCheckThread implements ThreadFactory{
@Override
public Thread newThread(@NotNull Runnable r){
public Thread newThread(@NonNull Runnable r){
Thread t = new Thread(r, "AdvancedServerList-UpdateThread");
t.setDaemon(true);
return t;
@@ -0,0 +1,54 @@
package ch.andre601.advancedserverlist.core.commands;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.CommandDescription;
import org.incendo.cloud.annotations.Permission;
import org.jspecify.annotations.Nullable;
@Command("advancedserverlist|asl")
@CommandDescription("Main Command of the plugin")
@Permission("advancedserverlist.admin")
@CommandType(CommandType.Type.ALL)
public record CmdClearCache(AdvancedServerList<?> core){
public static CmdClearCache create(AdvancedServerList<?> core){
return new CmdClearCache(core);
}
@Command("clearcache [target]")
@CommandDescription("Cleares the Favicon and/or Player Cache.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.clearcache"})
@CommandType(CommandType.Type.ALL)
public void handle(
CmdSender sender,
@Nullable @Argument(description = "The type of Cache to clean. Defaults to ALL.") CacheTarget target
){
if(target == null)
target = CacheTarget.ALL;
sender.sendPrefixedMsg("Clearing cache...");
if(target == CacheTarget.ALL || target == CacheTarget.FAVICON){
core().clearFaviconCache();
sender.sendPrefixedMsg("Cleared Favicon Cache.");
}
if(target == CacheTarget.ALL || target == CacheTarget.PLAYER){
core().clearPlayerCache();
sender.sendPrefixedMsg("Cleared Player Cache.");
}
sender.sendPrefixedMsg("<green>Cache clearing complete!");
}
public enum CacheTarget{
ALL,
FAVICON,
PLAYER
}
}
@@ -0,0 +1,65 @@
package ch.andre601.advancedserverlist.core.commands;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import net.kyori.adventure.text.format.NamedTextColor;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.annotation.specifier.Greedy;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.CommandDescription;
import org.incendo.cloud.annotations.Permission;
import org.incendo.cloud.annotations.suggestion.Suggestions;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.help.result.CommandEntry;
import org.incendo.cloud.minecraft.extras.MinecraftHelp;
import org.jspecify.annotations.Nullable;
import java.util.List;
@Command("advancedserverlist|asl")
@CommandDescription("Main Command of the plugin")
@Permission("advancedserverlist.admin")
@CommandType(CommandType.Type.ALL)
public record CmdHelp(CommandManager<CmdSender> manager, MinecraftHelp<CmdSender> help){
public static CmdHelp create(CommandManager<CmdSender> manager){
MinecraftHelp<CmdSender> help = MinecraftHelp.<CmdSender>builder()
.commandManager(manager)
.audienceProvider(CmdSender::audience)
.commandPrefix("/asl help")
.colors(MinecraftHelp.helpColors(
NamedTextColor.WHITE, NamedTextColor.AQUA, NamedTextColor.WHITE, NamedTextColor.GRAY, NamedTextColor.DARK_GRAY
))
.build();
return new CmdHelp(manager, help);
}
@Command("help [query]")
@CommandDescription("Displays all commands or provides info about a specific one.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.help"})
@CommandType(CommandType.Type.ALL)
public void handle(
CmdSender sender,
@Nullable @Argument(description = "Search Query for a specific command", suggestions = "help") @Greedy String query
){
this.help.queryCommands(query == null ? "" : query, sender);
}
@Suggestions("help")
public List<String> helpQueries(CommandContext<CmdSender> context) {
return this.manager.createHelpHandler()
.queryRootIndex(context.sender())
.entries()
.stream()
.filter(entry -> context.hasPermission(entry.command().commandPermission()))
.filter(entry -> {
CommandType.Type type = entry.command().commandMeta().getOrDefault(CommandHandler.COMMAND_TYPE, CommandType.Type.ALL);
return type == CommandType.Type.ALL || type == CommandType.Type.PLAYER_ONLY && context.sender().isPlayer();
})
.map(CommandEntry::syntax)
.toList();
}
}
@@ -0,0 +1,78 @@
package ch.andre601.advancedserverlist.core.commands;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import ch.andre601.advancedserverlist.core.migration.minimotd.MiniMOTDConfigMigrator;
import ch.andre601.advancedserverlist.core.migration.serverlistplus.SLPConfigMigrator;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.CommandDescription;
import org.incendo.cloud.annotations.Permission;
import org.jspecify.annotations.NonNull;
import java.util.Locale;
@Command("advancedserverlist|asl")
@CommandDescription("Main Command of the plugin")
@Permission("advancedserverlist.admin")
@CommandType(CommandType.Type.ALL)
public record CmdMigrate(AdvancedServerList<?> core){
public static CmdMigrate create(AdvancedServerList<?> core){
return new CmdMigrate(core);
}
@Command("migrate <plugin>")
@CommandDescription("Migrates Profiles from supported Plugins to ASL.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.migrate"})
@CommandType(CommandType.Type.ALL)
public void handle(
CmdSender sender,
@NonNull @Argument(description = "Name of the plugin to migrate from") MigratablePlugin plugin
){
if(plugin == MigratablePlugin.SERVERLISTPLUS){
if(!core().plugin().isPluginEnabled("ServerListPlus")){
sender.sendErrorMsg("<red>ServerListPlus not enabled.");
sender.sendErrorMsg("<red>The plugin needs to be enabled for the migration to work.");
return;
}
sender.sendPrefixedMsg("Migrating from ServerListPlus...");
int migrated = SLPConfigMigrator.migrate(core(), sender);
if(migrated == 0){
sender.sendErrorMsg("<red>Couldn't migrate any profiles from ServerListPlus.");
sender.sendErrorMsg("<red>See the server console for any errors.");
return;
}else{
sender.sendPrefixedMsg("<green>Successfully migrated </green>%d<green> Profile(s)!", migrated);
}
}else
if(plugin == MigratablePlugin.MINIMOTD){
sender.sendPrefixedMsg("Migrating from MiniMOTD...");
if(MiniMOTDConfigMigrator.migrate(core(), sender)){
sender.sendPrefixedMsg("<green>Successfully migrated config from MiniMOTD!");
}else{
sender.sendErrorMsg("<red>Couldn't migrate config from MiniMOTD.");
sender.sendErrorMsg("<red>See the server console for any errors.");
return;
}
}else{
sender.sendErrorMsg("<red>Received invalid Plugin </red>%s<red>!", plugin.toString());
sender.sendErrorMsg("<red>Only the following plugins are supported:");
for(MigratablePlugin pl : MigratablePlugin.values()){
sender.sendErrorMsg("- <click:suggest_command:/asl migrate %s>%s</click>", pl.name().toLowerCase(Locale.ROOT), pl.name().toLowerCase(Locale.ROOT));
}
}
sender.sendPrefixedMsg("<green>Run <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the new Profile(s).");
}
public enum MigratablePlugin{
SERVERLISTPLUS,
MINIMOTD
}
}
@@ -0,0 +1,483 @@
package ch.andre601.advancedserverlist.core.commands;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.CommandDescription;
import org.incendo.cloud.annotations.Permission;
import org.incendo.cloud.annotations.suggestion.Suggestions;
import org.incendo.cloud.context.CommandInput;
import org.jspecify.annotations.NonNull;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@Command("advancedserverlist|asl")
@CommandDescription("Main Command of the plugin.")
@Permission("advancedserverlist.admin")
@CommandType(CommandType.Type.ALL)
public record CmdProfiles(AdvancedServerList<?> core){
public static CmdProfiles create(AdvancedServerList<?> core){
return new CmdProfiles(core);
}
@Command("profiles add <name>")
@CommandDescription("Creates a new Profile with default values applied.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.add"})
@CommandType(CommandType.Type.ALL)
public void add(
CmdSender sender,
@NonNull @Argument(description = "Name of the profile to create.") String name
){
if(name.isEmpty()){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>A profile name needs to be provided.");
return;
}
if(CommandHandler.profile(core(), name) != null){
sender.sendErrorMsg("<red>A profile with the name </red>%s<red> already exists.", name);
return;
}
String file = CommandHandler.profileName(name);
if(core().fileHandler().createFile(file)){
sender.sendPrefixedMsg("<green>Successfully created </green>%s<green>!", file);
sender.sendPrefixedMsg("<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the file.");
}else{
sender.sendErrorMsg("<red>Error while creating new profile.");
sender.sendErrorMsg("<red>Check the server console for details.");
}
}
@Command("profiles copy <profile> <name>")
public void copy(
CmdSender sender,
@NonNull @Argument(description = "Name of the profile to copy.", suggestions = "profiles") String profile,
@NonNull @Argument(description = "Name of the copy to have.") String name
){
if(profile.isEmpty() || name.isEmpty()){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>A profile name and name for the copy need to be provided.");
return;
}
String profileName = CommandHandler.profileName(profile);
String copyName = CommandHandler.profileName(name);
ServerListProfile original = CommandHandler.profile(core(), profileName);
if(original == null){
sender.sendErrorMsg("<red>A profile with name </red>%s<red> does not exist.", profile);
return;
}
boolean copyExists = CommandHandler.profile(core(), copyName) != null;
if(copyExists){
sender.sendErrorMsg("<red>A profile with name </red>%s<red> already exists.", name);
return;
}
Path profilePath = core().plugin().folderPath().resolve("profiles").resolve(copyName);
if(!Files.exists(profilePath)){
try{
Files.createFile(profilePath);
}catch(IOException ex){
sender.sendErrorMsg("<red>Encountered an IOException while creating </red>%s<red>.", copyName);
sender.sendErrorMsg("<red>Please see the server console for further details.");
core.plugin().pluginLogger().warn("Encountered IOException while creating file <white>%s</white>", ex, copyName);
return;
}
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
.path(profilePath)
.indent(2)
.nodeStyle(NodeStyle.BLOCK)
.defaultOptions(opt -> opt.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
.build();
ConfigurationNode node;
try{
node = loader.load();
}catch(IOException ex){
sender.sendErrorMsg("<red>Encountered an IOException while loading file </red>%s<red>.", copyName);
sender.sendErrorMsg("<red>Please see the server console for further details.");
core().plugin().pluginLogger().warn("Encountered IOException while loading file <white>%s</white>.", ex, copyName);
return;
}
try{
node.node("priority").set(original.priority());
node.node("condition").set(original.condition());
node.node("profiles").setList(ProfileEntry.class, original.profiles());
node.set(ProfileEntry.class, original.defaultProfile());
}catch(SerializationException ex){
sender.sendErrorMsg("<red>Encountered a SerializationException while copying values from </red>%s<red> to </red>%s<red>.", profileName, copyName);
sender.sendErrorMsg("<red>Please see the server console for further details.");
core().plugin().pluginLogger().warn("<red>Encountered a SerializationException while copying values from </red>%s<red> to </red>%s<red>.", ex, profileName, copyName);
return;
}
try{
loader.save(node);
sender.sendPrefixedMsg("<green>Successfully created copy of </green>%s<green> as </green>%s<green>!", profileName, copyName);
sender.sendPrefixedMsg("<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the file.");
}catch(IOException ex){
sender.sendErrorMsg("<red>There was an IOException while loading file </red>%s<red>!", copyName);
sender.sendErrorMsg("<red>Please see the server console for further details.");
core.plugin().pluginLogger().warn("Encountered an IOException while loading file <white>%s</white>", ex, copyName);
}
}
}
@Command("profiles edit <profile>")
@CommandDescription("Opens a Dialog to edit a specific profile ingame.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.edit"})
@CommandType(CommandType.Type.PLAYER_ONLY)
public void edit(
CmdSender sender,
@NonNull @Argument(description = "Name of the profile to edit.", suggestions = "profiles") String profile
){
if(!core().plugin().isDialogsSupported()){
sender.sendErrorMsg("Dialogs are not supported on this server or proxy version.");
return;
}
ServerListProfile slp = CommandHandler.profile(core(), profile);
if(slp == null){
sender.sendErrorMsg("<red>A profile with name </red>%s<red> does not exist.", profile);
return;
}
IDialogList.IDialogListBuilder listBuilder = core().plugin().createDialogListBuilder(slp.file());
String warning = """
<gold><bold>WARNING!</bold></gold>
Dialog-based Profile editing is currently an <italic>experimental feature</italic>!
Please create backups of your profiles before using this feature and report any bugs and/or glitches you encounter.""";
listBuilder.appendBody(warning);
listBuilder.appendDialog(
createDialog("Main Settings", warning, slp, slp.defaultProfile(), slp.priority(), slp.condition(), -1)
);
for(int i = 0; i < slp.profiles().size(); i++){
listBuilder.appendDialog(
createDialog("Profiles #" + (i + 1), warning, slp, slp.profiles().get(i), -1, null, i)
);
}
listBuilder.build().show(sender);
}
@Command("profiles info <profile>")
@CommandDescription("Provides info about a specific profile.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.info"})
@CommandType(CommandType.Type.PLAYER_ONLY)
public void info(
CmdSender sender,
@NonNull @Argument(description = "Name of the profile to view.", suggestions = "profiles") String profile
){
if(profile.isEmpty()){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>A profile name needs to be provided.");
return;
}
ServerListProfile slp = CommandHandler.profile(core(), profile);
if(slp == null){
sender.sendErrorMsg("<red>Unable to find profile with name </red>%s<red>.", profile);
sender.sendErrorMsg("<red>Make sure you typed it correctly.");
return;
}
ProfileOptionsSender optionsSender = new ProfileOptionsSender(slp.file());
optionsSender
.append(
ProfileOptionsSender.OptionStringBuilder.of("Priority", slp.priority())
.option(ProfileOption.PRIORITY)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Condition", slp.condition())
.option(ProfileOption.CONDITION)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Profiles")
.color(slp.profiles().isEmpty() ? ProfileOptionsSender.ColorName.RED : ProfileOptionsSender.ColorName.GREEN)
);
if(!slp.profiles().isEmpty()){
for(int i = 0; i < slp.profiles().size(); i++){
optionsSender.append(
ProfileOptionsSender.OptionStringBuilder.of("#" + (i + 1), profileHover(slp.profiles().get(i)))
.prefix("│ %s─".formatted((i + 1) == slp.profiles().size() ? "└" : "├"))
.color(ProfileOptionsSender.ColorName.AQUA)
);
}
}
ProfileEntry entry = slp.defaultProfile();
optionsSender
.append(
ProfileOptionsSender.OptionStringBuilder.of("MOTD", entry.motd())
.option(ProfileOption.MOTD)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Favicon", entry.favicon())
.option(ProfileOption.FAVICON)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Player count")
.prefix("└─")
.color(ProfileOptionsSender.ColorName.AQUA)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count?", entry.hidePlayersEnabled())
.prefix(" ├─")
.option(ProfileOption.PLAYERCOUNT_HIDEPLAYERS)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count hover?", entry.hidePlayersHoverEnabled())
.prefix(" ├─")
.option(ProfileOption.PLAYERCOUNT_HIDEPLAYERSHOVER)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Player count hover", entry.players())
.prefix(" ├─")
.option(ProfileOption.PLAYERCOUNT_HOVER)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Player count text", entry.playerCountText())
.prefix(" ├─")
.option(ProfileOption.PLAYERCOUNT_TEXT)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Extra Players")
.prefix(" ├─")
.color(ProfileOptionsSender.ColorName.AQUA)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.extraPlayersEnabled())
.prefix(" │ ├─")
.option(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_ENABLED)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.extraPlayersCount())
.prefix(" │ └─")
.option(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_AMOUNT)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Max Players")
.prefix(" ├─")
.color(ProfileOptionsSender.ColorName.AQUA)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.maxPlayersEnabled())
.prefix(" │ ├─")
.option(ProfileOption.PLAYERCOUNT_MAXPLAYERS_ENABLED)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.maxPlayersCount())
.prefix(" │ └─")
.option(ProfileOption.PLAYERCOUNT_MAXPLAYERS_AMOUNT)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Online Players")
.prefix(" └─")
.color(ProfileOptionsSender.ColorName.AQUA)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.onlinePlayersEnabled())
.prefix(" ├─")
.option(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_ENABLED)
).append(
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.onlinePlayersCount())
.prefix(" └─")
.option(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_AMOUNT)
).send(sender);
}
@Command("profiles list")
@CommandDescription("Lists all available profiles with priority, conditions and if they are valid.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.list"})
@CommandType(CommandType.Type.ALL)
public void list(CmdSender sender){
sender.sendMsg();
sender.sendPrefixedMsg("Available Profiles:");
sender.sendMsg("<dark_grey>|");
List<ServerListProfile> profiles = core().fileHandler().profiles().stream()
.sorted(Comparator.comparingInt(ServerListProfile::priority).reversed())
.toList();
if(profiles.isEmpty()){
sender.sendMsg("<dark_grey></dark_grey> <i>No profiles found.</i>");
}else{
for(int i = 0; i < profiles.size(); i++){
sender.sendMsg(
"<dark_grey>%s</dark_grey> <aqua>" +
"<hover:show_text:\"%s\">" +
"<click:suggest_command:/asl profiles info %s>" +
"%s" +
"</click>" +
"</hover>" +
"</aqua>",
(i + 1) == profiles.size() ? "" : "-",
hover(profiles.get(i)),
profiles.get(i).file(),
profiles.get(i).file()
);
}
}
sender.sendMsg();
sender.sendMsg("<grey><i>Hover</i></grey> = Show details.");
sender.sendMsg("<grey><i>Click</i></grey> = Get Command.");
}
@Suggestions("profiles")
public List<String> profilesSuggestions(CommandInput input){
String name = input.readString();
List<String> profiles = core().fileHandler().profiles().stream()
.map(profile -> profile.file().substring(0, profile.file().lastIndexOf('.')))
.toList();
if(name.isEmpty())
return profiles;
List<String> matches = new ArrayList<>(profiles.size());
for(String str : profiles){
if(str.length() >= name.length() && str.regionMatches(true, 0, name, 0, name.length()))
matches.add(str);
}
return matches;
}
private String hover(ServerListProfile profile){
return """
<grey>Priority: <white>%d</white>
Condition: <white>%s</white>
Valid? %s""".formatted(
profile.priority(),
profile.condition() == null || profile.condition().isEmpty() ? "<i>None</i>" : profile.condition(),
profile.isInvalidProfile() ? "<red>No</red>" : "<green>Yes</green>"
);
}
private String profileHover(ProfileEntry entry){
return """
<grey>MOTD:
%s<reset>
<grey>Favicon: %s<reset>
<grey>Hide Player count? %s
Hide Player count Hover? %s
Player count Hover:
%s<reset>
<grey>Player count Text: %s<reset>
<grey>Extra Players: %s<reset>
<grey>Max Players: %s<reset>
<grey>Online Players: %s""".formatted(
entry.motd() == null || entry.motd().isEmpty() ?
"<i><white>None</white></i>" : String.join("<reset>\n", entry.motd()),
entry.favicon() == null || entry.favicon().isEmpty() ?
"<i><white>None</white></i>" : entry.favicon(),
entry.hidePlayersEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
entry.hidePlayersHoverEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
entry.players().isEmpty() ? "<i><white>None</white></i>" : String.join("<reset>\n", entry.players()),
entry.playerCountText() == null || entry.playerCountText().isEmpty() ?
"<i><white>None</white></i>" : entry.playerCountText(),
entry.extraPlayersEnabled().getOrDefault(false) ? entry.extraPlayersCount() : "<red>Disabled</red>",
entry.maxPlayersEnabled().getOrDefault(false) ? entry.maxPlayersCount() : "<red>Disabled</red>",
entry.onlinePlayersEnabled().getOrDefault(false) ? entry.onlinePlayersCount() : "<red>Disabled</red>"
);
}
private IDialog<?> createDialog(
String title,
String warning,
ServerListProfile slp,
ProfileEntry entry,
int priority,
String condition,
int index
){
IDialog.IDialogBuilder builder = core.plugin().createDialogBuilder(title, slp, index);
builder.appendBody(warning);
if(index < 0){
builder.appendNumberRange(ProfileOption.PRIORITY, "Priority", priority)
.appendTextInput(ProfileOption.CONDITION, "Condition", condition, 100);
}
builder.appendTextbox(ProfileOption.MOTD, "MOTD", entry.motd(), 200, 2)
.appendTextInput(ProfileOption.FAVICON, "Favicon", entry.favicon(), 100)
.appendBoolean(ProfileOption.PLAYERCOUNT_HIDEPLAYERS, "Hide Player Count", entry.hidePlayersEnabled())
.appendBoolean(ProfileOption.PLAYERCOUNT_HIDEPLAYERSHOVER, "Hide Player Count Hover", entry.hidePlayersHoverEnabled())
.appendTextbox(ProfileOption.PLAYERCOUNT_HOVER, "Player Count Hover", entry.players(), 200, 10)
.appendTextInput(ProfileOption.PLAYERCOUNT_TEXT, "Player Count Text", entry.playerCountText(), 100)
.appendBoolean(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_ENABLED, "Enable Extra Players", entry.extraPlayersEnabled())
.appendTextInput(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_AMOUNT, "Extra Players Count", entry.extraPlayersCount(), 100)
.appendBoolean(ProfileOption.PLAYERCOUNT_MAXPLAYERS_ENABLED, "Enable Max Players", entry.maxPlayersEnabled())
.appendTextInput(ProfileOption.PLAYERCOUNT_MAXPLAYERS_AMOUNT, "Max Players Count", entry.maxPlayersCount(), 100)
.appendBoolean(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_ENABLED, "Enable Online Players", entry.onlinePlayersEnabled())
.appendTextInput(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_AMOUNT, "Online Players Count", entry.onlinePlayersCount(), 100);
return builder.build();
}
public enum ProfileOption{
PRIORITY,
CONDITION,
MOTD,
FAVICON,
PLAYERCOUNT_HIDEPLAYERS,
PLAYERCOUNT_HIDEPLAYERSHOVER,
PLAYERCOUNT_HOVER,
PLAYERCOUNT_TEXT,
PLAYERCOUNT_EXTRAPLAYERS_ENABLED,
PLAYERCOUNT_EXTRAPLAYERS_AMOUNT,
PLAYERCOUNT_MAXPLAYERS_ENABLED,
PLAYERCOUNT_MAXPLAYERS_AMOUNT,
PLAYERCOUNT_ONLINEPLAYERS_ENABLED,
PLAYERCOUNT_ONLINEPLAYERS_AMOUNT;
public static List<String> list(){
return Arrays.stream(values())
.map(ProfileOption::toString)
.toList();
}
public static ProfileOption fromString(String input){
for(ProfileOption option : values()){
if(option.toString().equalsIgnoreCase(input))
return option;
}
return null;
}
@Override
public String toString(){
return this.name().toLowerCase(Locale.ROOT).replace("_", ".");
}
public String toDialogKey(){
return this.name().toLowerCase(Locale.ROOT);
}
}
}
@@ -0,0 +1,44 @@
package ch.andre601.advancedserverlist.core.commands;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.CommandDescription;
import org.incendo.cloud.annotations.Permission;
@Command("advancedserverlist|asl")
@CommandDescription("Main Command of the plugin")
@Permission("advancedserverlist.admin")
@CommandType(CommandType.Type.ALL)
public record CmdReload(AdvancedServerList<?> core){
public static CmdReload create(AdvancedServerList<?> core){
return new CmdReload(core);
}
@Command("reload")
@CommandDescription("Reloads the plugin's main config and its profiles.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.reload"})
@CommandType(CommandType.Type.ALL)
public void handle(CmdSender sender){
sender.sendPrefixedMsg("Reloading plugin...");
if(core().fileHandler().reloadConfig()){
sender.sendPrefixedMsg("<green>Reloaded </green>config.yml<green>!");
}else{
sender.sendErrorMsg("<red>Encountered an error while reloading the </red>config.yml<red>.");
sender.sendErrorMsg("<red>See the server console for details.");
}
if(core().fileHandler().reloadProfiles()){
sender.sendPrefixedMsg("<green>(Re)loaded <white>%d</white> Profile(s)!", core().fileHandler().profiles().size());
}else{
sender.sendErrorMsg("<red>Encountered errors while (re)loading profiles.");
sender.sendErrorMsg("<red>See the server console for details.");
}
sender.sendPrefixedMsg("<green>Reload complete!");
}
}
@@ -29,61 +29,16 @@ import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
import ch.andre601.advancedserverlist.core.migration.minimotd.MiniMOTDConfigMigrator;
import ch.andre601.advancedserverlist.core.migration.serverlistplus.SLPConfigMigrator;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
import net.kyori.adventure.text.format.NamedTextColor;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.annotation.specifier.Greedy;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.CommandDescription;
import org.incendo.cloud.annotations.Permission;
import org.incendo.cloud.annotations.suggestion.Suggestions;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.help.result.CommandEntry;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.minecraft.extras.MinecraftHelp;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@Command("advancedserverlist|asl")
@CommandDescription("Main command of the plugin.")
@Permission("advancedserverlist.admin")
@CommandType(CommandType.Type.ALL)
public class CommandHandler{
public static final CloudKey<CommandType.Type> COMMAND_TYPE = CloudKey.of("command_type", CommandType.Type.class);
public static final CloudKey<String> OPTION = CloudKey.of("profile_option", String.class);
public static final List<String> PROFILE_OPTIONS = List.of(
"priority",
"condition",
"motd",
"favicon",
"playercount.hideplayers",
"playercount.hideplayershover",
"playercount.hover",
"playercount.text",
"playercount.extraplayers.enabled",
"playercount.extraplayers.amount",
"playercount.maxplayers.enabled",
"playercount.maxplayers.amount",
"playercount.onlineplayers.enabled",
"playercount.onlineplayers.amount"
);
public static void handleSet(AdvancedServerList<?> core, CommandContext<CmdSender> context){
CmdSender sender = context.sender();
@@ -105,8 +60,8 @@ public class CommandHandler{
List<String> oldValues = new ArrayList<>();
List<String> newValues = new ArrayList<>();
switch(option.toLowerCase(Locale.ROOT)){
case "priority" -> {
switch(CmdProfiles.ProfileOption.fromString(option)){
case PRIORITY -> {
oldValues.add(String.valueOf(slp.priority()));
if(value == null || value.isEmpty()){
@@ -123,7 +78,7 @@ public class CommandHandler{
return;
}
}
case "condition" -> {
case CONDITION -> {
oldValues.add(slp.condition());
if(value == null || value.isEmpty()){
@@ -134,7 +89,7 @@ public class CommandHandler{
condition = value;
newValues.add(value);
}
case "motd" -> {
case MOTD -> {
oldValues.addAll(entry.motd());
if(value == null || value.isEmpty()){
@@ -142,7 +97,7 @@ public class CommandHandler{
break;
}
String[] lines = value.split("\\\\n|<newline>");
String[] lines = value.split("\\\\n|<newline>|<br>");
if(lines.length == 0){
builder.motd(Collections.emptyList());
break;
@@ -159,7 +114,7 @@ public class CommandHandler{
newValues.addAll(Arrays.asList(lines));
}
case "favicon" -> {
case FAVICON -> {
oldValues.add(entry.favicon());
if(value == null || value.isEmpty()){
@@ -171,7 +126,7 @@ public class CommandHandler{
newValues.add(value);
}
case "playercount.hideplayers" -> {
case PLAYERCOUNT_HIDEPLAYERS -> {
if(!entry.hidePlayersEnabled().isNotSet())
oldValues.add(String.valueOf(entry.hidePlayersEnabled().getOrDefault(false)));
@@ -185,7 +140,7 @@ public class CommandHandler{
newValues.add(String.valueOf(bool.getOrDefault(false)));
}
case "playercount.hideplayershover" -> {
case PLAYERCOUNT_HIDEPLAYERSHOVER -> {
if(!entry.hidePlayersHoverEnabled().isNotSet())
oldValues.add(String.valueOf(entry.hidePlayersHoverEnabled().getOrDefault(false)));
@@ -199,7 +154,7 @@ public class CommandHandler{
newValues.add(String.valueOf(bool.getOrDefault(false)));
}
case "playercount.hover" -> {
case PLAYERCOUNT_HOVER -> {
oldValues.addAll(entry.players());
if(value == null || value.isEmpty()){
@@ -217,7 +172,7 @@ public class CommandHandler{
newValues.addAll(Arrays.asList(lines));
}
case "playercount.text" -> {
case PLAYERCOUNT_TEXT -> {
if(!entry.playerCountText().isEmpty())
oldValues.add(entry.playerCountText());
@@ -230,7 +185,7 @@ public class CommandHandler{
newValues.add(value);
}
case "playercount.extraplayers.enabled" -> {
case PLAYERCOUNT_EXTRAPLAYERS_ENABLED -> {
if(!entry.extraPlayersEnabled().isNotSet())
oldValues.add(String.valueOf(entry.extraPlayersEnabled().getOrDefault(false)));
@@ -244,7 +199,7 @@ public class CommandHandler{
newValues.add(String.valueOf(bool.getOrDefault(false)));
}
case "playercount.extraplayers.amount" -> {
case PLAYERCOUNT_EXTRAPLAYERS_AMOUNT -> {
if(!entry.extraPlayersCount().isEmpty())
oldValues.add(entry.extraPlayersCount());
@@ -257,7 +212,7 @@ public class CommandHandler{
newValues.add(value);
}
case "playercount.maxplayers.enabled" -> {
case PLAYERCOUNT_MAXPLAYERS_ENABLED -> {
if(!entry.maxPlayersEnabled().isNotSet())
oldValues.add(String.valueOf(entry.maxPlayersEnabled().getOrDefault(false)));
@@ -271,7 +226,7 @@ public class CommandHandler{
newValues.add(String.valueOf(bool.getOrDefault(false)));
}
case "playercount.maxplayers.amount" -> {
case PLAYERCOUNT_MAXPLAYERS_AMOUNT -> {
if(!entry.maxPlayersCount().isEmpty())
oldValues.add(entry.extraPlayersCount());
@@ -284,7 +239,7 @@ public class CommandHandler{
newValues.add(value);
}
case "playercount.onlineplayers.enabled" -> {
case PLAYERCOUNT_ONLINEPLAYERS_ENABLED -> {
if(!entry.onlinePlayersEnabled().isNotSet())
oldValues.add(String.valueOf(entry.onlinePlayersEnabled().getOrDefault(false)));
@@ -298,7 +253,7 @@ public class CommandHandler{
newValues.add(String.valueOf(bool.getOrDefault(false)));
}
case "playercount.onlineplayers.amount" -> {
case PLAYERCOUNT_ONLINEPLAYERS_AMOUNT -> {
if(!entry.onlinePlayersCount().isEmpty())
oldValues.add(entry.onlinePlayersCount());
@@ -311,8 +266,8 @@ public class CommandHandler{
newValues.add(value);
}
default -> {
sender.sendErrorMsg("<red>Unknown option</red> %s<red>!", option);
case null, default -> {
sender.sendErrorMsg("<red>Unknown option </red>%s<red>!", option);
return;
}
}
@@ -355,14 +310,14 @@ public class CommandHandler{
}
}
private static ServerListProfile profile(AdvancedServerList<?> core, String name){
public static ServerListProfile profile(AdvancedServerList<?> core, String name){
return core.fileHandler().profiles().stream()
.filter(p -> p.file().equalsIgnoreCase(profileName(name)))
.findFirst()
.orElse(null);
}
private static String profileName(String name){
public static String profileName(String name){
if(name == null || name.isEmpty())
return "";
@@ -390,567 +345,4 @@ public class CommandHandler{
default -> obj.toString();
};
}
private final CommandManager<CmdSender> commandManager;
private final MinecraftHelp<CmdSender> help;
public CommandHandler(CommandManager<CmdSender> commandManager){
this.commandManager = commandManager;
this.help = MinecraftHelp.<CmdSender>builder()
.commandManager(commandManager)
.audienceProvider(CmdSender::audience)
.commandPrefix("/advancedserverlist help")
.colors(MinecraftHelp.helpColors(
NamedTextColor.WHITE, NamedTextColor.AQUA, NamedTextColor.WHITE, NamedTextColor.GRAY, NamedTextColor.DARK_GRAY
))
.build();
}
@Command("help [query]")
@CommandDescription("Displays the commands available for AdvancedServerList")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.help"})
@CommandType(CommandType.Type.ALL)
public void help(
CmdSender sender,
@Nullable @Argument(description = "Query to receive info of a specific command.", suggestions = "help") @Greedy String query
){
this.help.queryCommands(query == null ? "" : query, sender);
}
@Command("reload")
@CommandDescription("Reloads the config.yml and all existing profiles.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.reload"})
@CommandType(CommandType.Type.ALL)
public void reload(CmdSender sender, AdvancedServerList<?> core){
sender.sendPrefixedMsg("Reloading plugin...");
if(core.fileHandler().reloadConfig()){
sender.sendPrefixedMsg("<green>Reloaded </green>config.yml<green>!");
}else{
sender.sendErrorMsg("<red>Error while reloading </red>config.yml<red>.");
sender.sendErrorMsg("<red>Check console for details.");
}
if(core.fileHandler().reloadProfiles()){
sender.sendPrefixedMsg("<green>(Re)loaded </green>%d<green> Profile(s)!", core.fileHandler().profiles().size());
}else{
sender.sendErrorMsg("<red>Error while (re)loading profiles.");
sender.sendErrorMsg("<red>Check console for details.");
}
sender.sendPrefixedMsg("<green>Reload complete!");
}
@Command("clearcache")
@CommandDescription("Clears the Favicon and Player cache of the plugin.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.clearcache"})
@CommandType(CommandType.Type.ALL)
public void clearCache(CmdSender sender, AdvancedServerList<?> core){
sender.sendPrefixedMsg("Clearing cache...");
core.clearFaviconCache();
sender.sendPrefixedMsg("Cleared Favicon cache.");
core.clearPlayerCache();
sender.sendPrefixedMsg("Cleared Player cache.");
sender.sendPrefixedMsg("<green>Cache clearing complete!");
}
@Command("migrate <plugin>")
@CommandDescription("Migrates Profiles from other plugins to itself.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.migrate"})
@CommandType(CommandType.Type.ALL)
public void migrate(
CmdSender sender,
AdvancedServerList<?> core,
@NonNull @Argument(description = "The plugin to migrate from.") Plugin plugin
){
if(plugin == Plugin.SERVERLISTPLUS){
if(!core.plugin().isPluginEnabled("ServerListPlus")){
sender.sendErrorMsg("<red>ServerListPlus is not enabled.");
sender.sendErrorMsg("<red>The plugin is required for the migration to work.");
return;
}
sender.sendPrefixedMsg("Migrating from ServerListPlus...");
int migrated = SLPConfigMigrator.migrate(core, sender);
if(migrated == 0){
sender.sendErrorMsg("<red>Unable to migrate any profiles from ServerListPlus.");
sender.sendErrorMsg("<red>Check console for details.");
}else{
sender.sendPrefixedMsg("<green>Successfully migrated </green>%d<green> Profile(s)", migrated);
}
}else
if(plugin == Plugin.MINIMOTD){
sender.sendPrefixedMsg("Migrating from MiniMOTD...");
if(MiniMOTDConfigMigrator.migrate(core, sender)){
sender.sendPrefixedMsg("<green>Successfully migrated from MiniMOTD!");
}else{
sender.sendErrorMsg("<red>Unable to migrate from MiniMOTD.");
sender.sendErrorMsg("<red>Check console for details.");
}
}else{
sender.sendErrorMsg("<red>Received invalid Plugin name </red>%s<red>.", plugin);
sender.sendMsg("<grey>Supported plugins [Click for command]:");
sender.sendMsg();
sender.sendMsg(" <grey>-</grey> <click:suggest_command:/asl migrate serverlistplus>ServerListPlus</click>");
sender.sendMsg(" <grey>-</grey> <click:suggest_command:/asl migrate minimotd>MiniMOTD</click>");
}
}
@Command("profiles list")
@CommandDescription("Lists all available profiles with their priority, conditions and if they are valid.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.list"})
@CommandType(CommandType.Type.ALL)
public void list(CmdSender sender, AdvancedServerList<?> core){
sender.sendMsg();
sender.sendPrefixedMsg("Available Profiles");
sender.sendMsg("<dark_grey>│");
List<ServerListProfile> profiles = core.fileHandler().profiles().stream()
.sorted(Comparator.comparingInt(ServerListProfile::priority).reversed())
.toList();
if(profiles.isEmpty()){
sender.sendMsg("<dark_grey>└─</dark_grey> <i>No profiles found</i>");
}else{
for(int i = 0; i < profiles.size(); i++){
sender.sendMsg(
"<dark_grey>%s─</dark_grey> <aqua>" +
"<hover:show_text:\"%s\">" +
"<click:suggest_command:/asl profiles info %s>" +
"%s" +
"</click>" +
"</hover>" +
"</aqua>",
(i + 1) == profiles.size() ? "└" : "├",
hover(profiles.get(i)),
profiles.get(i).file(),
profiles.get(i).file()
);
}
}
if(sender.isPlayer()){
sender.sendMsg();
sender.sendMsg("<grey>[<white>Hover a name for details. Click for a command</white>]</grey>");
}
sender.sendMsg();
}
@Command("profiles info <profile>")
@CommandDescription("Provides info about a profile.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.info"})
@CommandType(CommandType.Type.PLAYER_ONLY)
public void info(
CmdSender sender,
AdvancedServerList<?> core,
@NonNull @Argument(description = "Name of the profile to view.", suggestions = "profiles") String profile
){
if(profile.isEmpty()){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>Please provide a proper profile name.");
return;
}
ServerListProfile slp = profile(core, profile);
if(slp == null){
sender.sendErrorMsg("<red>Unable to find profile with name </red>%s<red>.", profile);
sender.sendErrorMsg("<red>Make sure you typed it correctly.");
return;
}
ProfileOptionsSender optionsSender = new ProfileOptionsSender(slp.file());
optionsSender
.append(
ProfileOptionsSender.OptionStringBuilder.of("Priority", slp.priority())
.option("priority")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Condition", slp.condition())
.option("condition")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Profiles")
.color(slp.profiles().isEmpty() ? ProfileOptionsSender.ColorName.RED : ProfileOptionsSender.ColorName.GREEN)
);
if(!slp.profiles().isEmpty()){
for(int i = 0; i < slp.profiles().size(); i++){
optionsSender.append(
ProfileOptionsSender.OptionStringBuilder.of("#" + (i + 1), profileHover(slp.profiles().get(i)))
.prefix("│ %s─".formatted((i + 1) == slp.profiles().size() ? "└" : "├"))
.color(ProfileOptionsSender.ColorName.AQUA)
);
}
}
ProfileEntry entry = slp.defaultProfile();
optionsSender
.append(
ProfileOptionsSender.OptionStringBuilder.of("MOTD", entry.motd())
.option("motd")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Favicon", entry.favicon())
.option("favicon")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Player count")
.prefix("└─")
.color(ProfileOptionsSender.ColorName.AQUA)
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count?", entry.hidePlayersEnabled())
.prefix(" ├─")
.option("playercount.hideplayers")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count hover?", entry.hidePlayersHoverEnabled())
.prefix(" ├─")
.option("playercount.hideplayershover")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Player count hover", entry.players())
.prefix(" ├─")
.option("playercount.hover")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Player count text", entry.playerCountText())
.prefix(" ├─")
.option("playercount.text")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Extra Players")
.prefix(" ├─")
.color(ProfileOptionsSender.ColorName.AQUA)
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.extraPlayersEnabled())
.prefix(" │ ├─")
.option("playercount.extraplayers.enabled")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.extraPlayersCount())
.prefix(" │ └─")
.option("playercount.extraplayers.amount")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Max Players")
.prefix(" ├─")
.color(ProfileOptionsSender.ColorName.AQUA)
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.maxPlayersEnabled())
.prefix(" │ ├─")
.option("playercount.maxplayers.enabled")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.maxPlayersCount())
.prefix(" │ └─")
.option("playercount.maxplayers.amount")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Online Players")
.prefix(" └─")
.color(ProfileOptionsSender.ColorName.AQUA)
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.onlinePlayersEnabled())
.prefix(" ├─")
.option("playercount.onlineplayers.enabled")
)
.append(
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.onlinePlayersCount())
.prefix(" └─")
.option("playercount.onlineplayers.amount")
)
.send(sender);
}
@Command("profiles add <name>")
@CommandDescription("Creates a new profile with default values applied.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.add"})
@CommandType(CommandType.Type.ALL)
public void add(
CmdSender sender,
AdvancedServerList<?> core,
@NonNull @Argument(description = "Name of the profile to create.") String name
){
if(name.isEmpty()){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>Please provide a proper file name.");
return;
}
if(profile(core, name) != null){
sender.sendErrorMsg("<red>A profile with name </red>%s<red> already exists.", name);
return;
}
String fileName = profileName(name);
if(core.fileHandler().createFile(fileName)){
sender.sendPrefixedMsg("<green>Successfully created </green>%s<green>!", fileName);
sender.sendPrefixedMsg("<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the file.");
}else{
sender.sendErrorMsg("<red>Error while creating new profile.");
sender.sendErrorMsg("<red>Check console for details.");
}
}
@Command("profiles copy <profile> <name>")
@CommandDescription("Creates a copy of an existing profile.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.copy"})
@CommandType(CommandType.Type.ALL)
public void copy(
CmdSender sender,
AdvancedServerList<?> core,
@NonNull @Argument(description = "Name of the profile to copy.", suggestions = "profiles") String profile,
@NonNull @Argument(description = "Name of the copy.") String name
){
if(profile.isEmpty() || name.isEmpty()){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>Please provide a profile name and name for the copy.");
return;
}
String profileName = profileName(profile);
String copyName = profileName(name);
ServerListProfile targetProfile = profile(core, profile);
boolean copyExists = profile(core, name) != null;
if(targetProfile == null){
sender.sendErrorMsg("<red>No profile with name </red>%s<red> exists.", profile);
return;
}
if(copyExists){
sender.sendErrorMsg("<red>A file with name </red>%<red> already exists!", copyName);
return;
}
Path profilePath = core.plugin().folderPath().resolve("profiles").resolve(copyName);
if(!Files.exists(profilePath)){
try{
Files.createFile(profilePath);
}catch(IOException ex){
sender.sendErrorMsg("<red>Encountered IOException while creating file </red>%s<red>.", copyName);
sender.sendErrorMsg("<red>Check console for details.");
core.plugin().pluginLogger().warn("Encountered IOException while creating file <white>%s</white>", ex, copyName);
return;
}
}
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
.path(profilePath)
.indent(2)
.nodeStyle(NodeStyle.BLOCK)
.defaultOptions(opt -> opt.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
.build();
ConfigurationNode node;
try{
node = loader.load();
}catch(IOException ex){
sender.sendErrorMsg("<red>There was an IOException while loading file </red>%s<red>!", copyName);
sender.sendErrorMsg("<red>Check console for details.");
core.plugin().pluginLogger().warn("Encountered IOException while loading file <white>%s</white>", ex, copyName);
return;
}
try{
node.node("priority").set(targetProfile.priority());
node.node("condition").set(targetProfile.condition());
node.node("profiles").setList(ProfileEntry.class, targetProfile.profiles());
node.set(ProfileEntry.class, targetProfile.defaultProfile());
}catch(SerializationException ex){
sender.sendErrorMsg("<red>There was a SerializationException while copying values from </red>%s<red>.", profile);
sender.sendErrorMsg("<red>Check console for details.");
core.plugin().pluginLogger().warn("Encountered IOException while copying data from <white>%s</white> to <white>%s</white>.", ex, profileName, copyName);
return;
}
try{
loader.save(node);
sender.sendPrefixedMsg("<green>Successfully made copy of </green>%s<green> as </green>%s<green>!", profile, copyName);
sender.sendPrefixedMsg("<green>Use </green><click:suggest_command:/asl reload>/asl reload</click><green> to load the file.");
}catch(IOException ex){
sender.sendErrorMsg("<red>There was an IOException while loading file </red>%s<red>!", copyName);
sender.sendErrorMsg("<red>Check console for details.");
core.plugin().pluginLogger().warn("Encountered IOException while loading file <white>%s</white>", ex, copyName);
}
}
@Command("profiles edit <profile>")
@CommandDescription("Opens a Dialog to edit a profile.")
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.edit"})
@CommandType(CommandType.Type.PLAYER_ONLY)
public void edit(
CmdSender sender,
AdvancedServerList<?> core,
@NonNull @Argument(description = "Name of the profile to edit.", suggestions = "profiles") String profile
){
if(!core.plugin().isDialogsSupported()){
sender.sendErrorMsg("This command requires the new Dialog feature to be available!");
return;
}
ServerListProfile slp = profile(core, profile);
if(slp == null){
sender.sendErrorMsg("No profile with name <white>%s</white> found.", profile);
return;
}
IDialogList.IDialogListBuilder listBuilder = core.plugin().createDialogListBuilder(slp.file());
String warning = """
<gold><b>WARNING!</b></gold>
Dialog-based profile editing is currently an <i>experimental feature</i>!
Please create backups first before using it and report any bugs and/or glitches you may find.""";
listBuilder.appendBody(warning);
listBuilder.appendDialog(
createDialog(core, "Main Settings", warning, slp, slp.defaultProfile(), slp.priority(), slp.condition(), -1)
);
for(int i = 0; i < slp.profiles().size(); i++){
listBuilder.appendDialog(
createDialog(core, "Profiles <aqua>#" + (i + 1), warning, slp, slp.profiles().get(i), -1, null, i)
);
}
listBuilder.build().show(sender);
}
@Suggestions("help")
public List<String> helpQueries(CommandContext<CmdSender> context){
return this.commandManager.createHelpHandler()
.queryRootIndex(context.sender())
.entries()
.stream()
.filter(entry -> context.hasPermission(entry.command().commandPermission()))
.filter(entry -> {
CommandType.Type type = entry.command().commandMeta().getOrDefault(COMMAND_TYPE, CommandType.Type.ALL);
return type == CommandType.Type.ALL || type == CommandType.Type.PLAYER_ONLY && context.sender().isPlayer();
})
.map(CommandEntry::syntax)
.toList();
}
@Suggestions("profiles")
public List<String> profilesSuggestions(CommandInput input, AdvancedServerList<?> core){
String name = input.readString();
List<String> profiles = core.fileHandler().profiles().stream()
.map(profile -> profile.file().substring(0, profile.file().lastIndexOf('.')))
.toList();
if(name.isEmpty())
return profiles;
List<String> matches = new ArrayList<>(profiles.size());
for(String str : profiles){
if(str.length() >= name.length() && str.regionMatches(true, 0, name, 0, name.length()))
matches.add(str);
}
return matches;
}
private String hover(ServerListProfile profile){
return """
<grey>Priority: <white>%d</white>
Condition: <white>%s</white>
Is valid? %s""".formatted(
profile.priority(),
profile.condition() == null || profile.condition().isEmpty() ? "<i>None</i>" : profile.condition(),
profile.isInvalidProfile() ? "<red>No</red>" : "<green>Yes</green>"
);
}
private String profileHover(ProfileEntry entry){
return """
<grey>MOTD:
%s<reset>
<grey>Favicon: %s<reset>
<grey>Hide Playercount? %s
Hide Playercount Hover? %s
Playercount Hover:
%s<reset>
<grey>Playercount Text: %s<reset>
<grey>Extra Players: %s<reset>
<grey>Max Players: %s<reset>
<grey>Online Players: %s""".formatted(
entry.motd() == null || entry.motd().isEmpty() ?
"<i><white>None</white></i>" : String.join("<reset>\n", entry.motd()),
entry.favicon() == null || entry.favicon().isEmpty() ?
"<i><white>None</white></i>" : entry.favicon(),
entry.hidePlayersEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
entry.hidePlayersHoverEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
entry.players().isEmpty() ? "<i><white>None</white></i>" : String.join("<reset>\n", entry.players()),
entry.playerCountText() == null || entry.playerCountText().isEmpty() ?
"<i><white>None</white></i>" : entry.playerCountText(),
entry.extraPlayersEnabled().getOrDefault(false) ? entry.extraPlayersCount() : "<red>Disabled</red>",
entry.maxPlayersEnabled().getOrDefault(false) ? entry.maxPlayersCount() : "<red>Disabled</red>",
entry.onlinePlayersEnabled().getOrDefault(false) ? entry.onlinePlayersCount() : "<red>Disabled</red>"
);
}
private IDialog<?> createDialog(
AdvancedServerList<?> core,
String title,
String warning,
ServerListProfile slp,
ProfileEntry entry,
int priority,
String condition,
int index
){
IDialog.IDialogBuilder builder = core.plugin().createDialogBuilder(title, slp, index);
builder.appendBody(warning);
if(index < 0){
builder.appendNumberRange("priority", "Priority", priority)
.appendTextInput("condition", "Condition", condition, 100);
}
builder.appendTextbox("motd", "MOTD", entry.motd(), 100, 2)
.appendTextInput("favicon", "Favicon", entry.favicon(), 100)
.appendBoolean("hidePlayers", "Hide Player Count", entry.hidePlayersEnabled())
.appendBoolean("hidePlayersHover", "Hide Player Count Hover", entry.hidePlayersHoverEnabled())
.appendTextbox("hover", "Player Count Hover", entry.players(), 200, 10)
.appendTextInput("text", "Player Count Text", entry.playerCountText(), 100)
.appendBoolean("extraPlayersEnabled", "Enable Extra Players", entry.extraPlayersEnabled())
.appendTextInput("extraPlayersCount", "Extra Players Count", entry.extraPlayersCount(), 100)
.appendBoolean("maxPlayersEnabled", "Enable Max Players", entry.maxPlayersEnabled())
.appendTextInput("maxPlayersCount", "Max Players Count", entry.maxPlayersCount(), 100)
.appendBoolean("onlinePlayersEnabled", "Enable Online Players", entry.onlinePlayersEnabled())
.appendTextInput("onlinePlayersCount", "Online Players Count", entry.onlinePlayersCount(), 100);
return builder.build();
}
public enum Plugin {
SERVERLISTPLUS,
MINIMOTD
}
}
@@ -90,7 +90,7 @@ public class ProfileOptionsSender{
private String prefix = "├─";
private ColorName color = ColorName.AQUA;
private String hover = "<i>Not set</i>";
private String option = null;
private CmdProfiles.ProfileOption option = null;
private OptionStringBuilder(String displayName){
this.displayName = displayName;
@@ -116,7 +116,7 @@ public class ProfileOptionsSender{
return this;
}
public OptionStringBuilder option(String option){
public OptionStringBuilder option(CmdProfiles.ProfileOption option){
this.option = option;
return this;
}
@@ -135,7 +135,7 @@ public class ProfileOptionsSender{
.append("\">");
}
if(option != null && !option.isEmpty() && file != null && !file.isEmpty()){
if(option != null && file != null && !file.isEmpty()){
builder.append("<click:suggest_command:/asl profiles set ")
.append(file)
.append(" ")
@@ -145,7 +145,7 @@ public class ProfileOptionsSender{
builder.append(displayName);
if(option != null && !option.isEmpty() && file != null && !file.isEmpty())
if(option != null && file != null && !file.isEmpty())
builder.append("</click>");
if(hover != null && !hover.isEmpty())
@@ -1,6 +1,7 @@
package ch.andre601.advancedserverlist.core.interfaces.dialogs;
import ch.andre601.advancedserverlist.api.objects.NullBool;
import ch.andre601.advancedserverlist.core.commands.CmdProfiles;
import java.util.List;
@@ -10,13 +11,13 @@ public interface IDialog<T>{
interface IDialogBuilder{
IDialogBuilder appendBody(String body);
IDialogBuilder appendTextInput(String key, String title, String initValue, int maxLength);
IDialogBuilder appendTextInput(CmdProfiles.ProfileOption option, String title, String initValue, int maxLength);
IDialogBuilder appendTextbox(String key, String title, List<String> initValue, int maxLength, int rows);
IDialogBuilder appendTextbox(CmdProfiles.ProfileOption option, String title, List<String> initValue, int maxLength, int rows);
IDialogBuilder appendNumberRange(String key, String title, int initValue);
IDialogBuilder appendNumberRange(CmdProfiles.ProfileOption option, String title, int initValue);
IDialogBuilder appendBoolean(String key, String title, NullBool initValue);
IDialogBuilder appendBoolean(CmdProfiles.ProfileOption option, String title, NullBool initValue);
IDialog<?> build();
}
@@ -48,7 +48,16 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
ParseWarnCollector collector = new ParseWarnCollector(condition);
PluginLogger logger = core.plugin().pluginLogger();
boolean result = core.parser().evaluate(condition, player, server, collector);
boolean result;
try{
result = core.parser().compileToBoolean(condition, collector, player, server);
}catch(Exception ex){
logger.warn("Encountered an Exception while parsing condition '%s'. Cause: %s", condition, ex.getMessage());
if(core.fileHandler().getBool(false, "debug"))
logger.warn("Stacktrace:", ex);
return false;
}
if(collector.hasWarnings()){
logger.warn("Encountered <white>%d</white> Error(s) while parsing condition for file '<white>%s</white>':", collector.getWarnings().size(), file);
@@ -70,7 +79,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
}
if(profiles.size() == 1)
return profiles.get(0); // No need to run a random for 1 profile.
return profiles.getFirst(); // No need to run a random for 1 profile.
synchronized(random){
return profiles.get(random.nextInt(profiles.size()));
@@ -1,82 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.profiles.conditions;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderTokenReader;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderValueReader;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.CustomExpressionTokenizer;
import ch.andre601.expressionparser.ExpressionParserEngine;
import ch.andre601.expressionparser.ParseWarnCollector;
import ch.andre601.expressionparser.operator.Operator;
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
import ch.andre601.expressionparser.parsers.ValueReader;
import ch.andre601.expressionparser.templates.ExpressionTemplate;
import ch.andre601.expressionparser.tokens.Token;
import ch.andre601.expressionparser.tokens.readers.TokenReader;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.List;
public class ProfileConditionParser implements ExpressionParserEngine{
private final CustomExpressionTokenizer tokenizer;
private final ExpressionTemplateParser parser;
private ProfileConditionParser(List<TokenReader> tokenReaders, ImmutableMap<Token, Operator> operators, ImmutableList<ValueReader> valueReaders){
this.tokenizer = new CustomExpressionTokenizer(tokenReaders);
this.parser = new ExpressionTemplateParser(operators, valueReaders);
}
public static ProfileConditionParser create(){
return new ProfileConditionParserBuilder().addDefaults()
.addTokenReader(new PlaceholderTokenReader(-20))
.addValueReader(new PlaceholderValueReader())
.build();
}
public boolean evaluate(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
ExpressionTemplate result = parser.parse(tokenizer.parse(text, player, server, collector), collector);
if(result == null)
return false;
return result.returnBooleanExpression().evaluate();
}
@Override
public ExpressionTemplate compile(String s, ParseWarnCollector parseWarnCollector){
return null;
}
private static class ProfileConditionParserBuilder extends ExpressionParserEngine.Builder<ProfileConditionParser>{
@Override
public ProfileConditionParser build(){
return new ProfileConditionParser(this.getTokenReaders(), ImmutableMap.copyOf(this.getOperators()), ImmutableList.copyOf(this.getValueReaders()));
}
}
}
@@ -1,48 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.expressionparser.ParseWarnCollector;
import ch.andre601.expressionparser.tokens.Token;
import ch.andre601.expressionparser.tokens.readers.TokenReader;
import java.text.ParsePosition;
public abstract class CustomTokenReader extends TokenReader{
public CustomTokenReader(int priority){
super(priority);
}
@Override
public Token read(String text, ParsePosition position, ParseWarnCollector collector){
return null;
}
public abstract Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector);
}
@@ -1,92 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.CustomTokenReader;
import ch.andre601.expressionparser.ParseWarnCollector;
import ch.andre601.expressionparser.tokens.Token;
import ch.andre601.expressionparser.tokens.readers.TokenReader;
import com.google.common.collect.Ordering;
import java.text.ParsePosition;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class CustomExpressionTokenizer{
private static final Ordering<TokenReader> TOKEN_READER_ORDERING = Ordering.from(Comparator.comparingInt(TokenReader::getPriority)).reverse();
private final List<TokenReader> tokenReaders;
public CustomExpressionTokenizer(Iterable<TokenReader> tokenReaders){
this.tokenReaders = TOKEN_READER_ORDERING.immutableSortedCopy(tokenReaders);
}
public List<Token> parse(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
ParsePosition position = new ParsePosition(0);
List<Token> tokens = new LinkedList<>();
next_token:
while(true){
while(position.getIndex() < text.length() && Character.isWhitespace(text.charAt(position.getIndex())))
position.setIndex(position.getIndex() + 1);
if(position.getIndex() >= text.length())
break;
for(TokenReader tokenReader : tokenReaders){
Token token;
if(tokenReader instanceof CustomTokenReader customTokenReader){
if(null != (token = customTokenReader.read(text, position, player, server, collector))){
tokens.add(token);
continue next_token;
}
}else{
if(null != (token = tokenReader.read(text, position, collector))){
tokens.add(token);
continue next_token;
}
}
}
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;
}
return tokens;
}
}
@@ -23,27 +23,46 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
package ch.andre601.advancedserverlist.core.profiles.conditions.reader;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.PlaceholderToken;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.expressionparser.ParseWarnCollector;
import ch.andre601.expressionparser.tokens.Token;
import ch.andre601.expressionparser.tokens.readers.TokenReader;
import java.text.ParsePosition;
public class PlaceholderTokenReader extends CustomTokenReader{
public class PlaceholderTokenReader extends TokenReader{
public PlaceholderTokenReader(int priority){
super(priority);
public PlaceholderTokenReader(){
super(-20);
}
@Override
public Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
public Token read(String text, ParsePosition position, ParseWarnCollector collector, Object... args){
GenericPlayer player = null;
GenericServer server = null;
for(Object arg : args){
if(arg instanceof GenericPlayer pl){
player = pl;
}else
if(arg instanceof GenericServer srv){
server = srv;
}
}
if(player == null || server == null){
collector.appendWarning(position.getIndex(), "Received null GenericPlayer or GenericServer instance.");
return null;
}
if(position.getIndex() + 1 < text.length() && text.charAt(position.getIndex()) == '$' && text.charAt(position.getIndex() + 1) == '{'){
position.setIndex(position.getIndex() + 2);
return new PlaceholderToken(StringReplacer.parsePlaceholder(text, position, player, server, collector));
}
return null;
@@ -23,9 +23,9 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
package ch.andre601.advancedserverlist.core.profiles.conditions.reader;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.PlaceholderToken;
import ch.andre601.expressionparser.ParseWarnCollector;
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
import ch.andre601.expressionparser.parsers.ValueReader;
@@ -37,8 +37,8 @@ import java.util.List;
public class PlaceholderValueReader extends ValueReader{
@Override
public ExpressionTemplate read(ExpressionTemplateParser parser, List<Token> tokens, ParseWarnCollector collector){
if(tokens.get(0) instanceof PlaceholderToken){
PlaceholderToken token = (PlaceholderToken)tokens.remove(0);
if(tokens.getFirst() instanceof PlaceholderToken){
PlaceholderToken token = (PlaceholderToken)tokens.removeFirst();
return token.getValue();
}
return null;
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
package ch.andre601.advancedserverlist.core.profiles.conditions.tokens;
import ch.andre601.expressionparser.expressions.ToBooleanExpression;
import ch.andre601.expressionparser.expressions.ToDoubleExpression;
@@ -30,7 +30,7 @@ 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;
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.PlaceholderToken;
import ch.andre601.expressionparser.ParseWarnCollector;
import java.text.ParsePosition;
@@ -25,27 +25,35 @@
package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.expressionparser.DefaultExpressionParserEngine;
import ch.andre601.expressionparser.ParseWarnCollector;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import java.util.Map;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ExpressionParserTests{
private final ProfileConditionParser parser = ProfileConditionParser.create();
private final DefaultExpressionParserEngine parser = DefaultExpressionParserEngine.createDefault();
private final DummyPluginLogger logger = new DummyPluginLogger();
private final Map<String, Boolean> testValuesMap = getTestMap();
private final TestPlayer player = new TestPlayer();
private final TestServer server = new TestServer();
@Test
public void testBasicExpressionResults(){
for(Map.Entry<String, Boolean> values : testValuesMap.entrySet()){
logger.info("TEST[expression=\"%s\", expected=%b]", values.getKey(), values.getValue());
ParseWarnCollector collector = new ParseWarnCollector(values.getKey());
boolean result = parser.evaluate(values.getKey(), null, null, collector);
boolean result = parser.compileToBoolean(values.getKey(), collector, player, server);
logger.info("Result (Output, Expected?): %b, %b", result, (result == values.getValue()));
assertEquals(result, values.getValue());
@@ -66,4 +74,38 @@ public class ExpressionParserTests{
"false or 100 < 10", false
);
}
private static class TestPlayer implements GenericPlayer{
@Override
public @NonNull String getName(){
return "Lorem";
}
@Override
public int getProtocol(){
return 1;
}
@Override
public @NonNull UUID getUUID(){
return UUID.randomUUID();
}
}
private static class TestServer implements GenericServer{
@Override
public int getPlayersOnline(){
return 10;
}
@Override
public int getPlayersMax(){
return 20;
}
@Override
public @Nullable String getHost(){
return "play.example.com";
}
}
}
+1 -3
View File
@@ -1,7 +1,5 @@
{% extends "base.html" %}
{% block announce %}
<span class="twemoji balloon">{% include ".icons/material/balloon.svg" %}</span>
<span class="rainbow">Celebrating <b>50,000 downloads</b> of AdvancedServerList! THANK YOU!</span>
<span class="twemoji balloon">{% include ".icons/material/balloon.svg" %}</span>
<span class="rainbow"><span class="balloon twemoji">{% include ".icons/material/balloon.svg" %}</span> <b>100 THOUSAND downloads</b> on <a class="modrinth" href="https://modrinth.com/plugin/advancedserverlist" target="_blank" rel="nofollow"><span class="twemoji">{% include ".icons/simple/modrinth.svg" %}</span> <b>Modrinth!</b></a> <span class="balloon2 twemoji">{% include ".icons/material/balloon.svg" %}</span><br><b>THANK YOU!</b></span>
{% endblock %}
+44
View File
@@ -100,6 +100,42 @@
}
}
@keyframes balloon2 {
0% {
transform: translate(0rem, 0rem) rotate(0deg) scale(2);
}
10% {
transform: translate(0.02rem, -0.04rem) rotate(5deg) scale(1.75);
}
20% {
transform: translate(-0.09rem, 0.08rem) rotate(-1deg) scale(2);
}
30% {
transform: translate(0.05rem, -0.06rem) rotate(3deg) scale(2.2);
}
40% {
transform: translate(-0.03rem, -0.09rem) rotate(-1.5deg) scale(1.85);
}
50% {
transform: translate(0.04rem, 0.1rem) rotate(1deg) scale(2);
}
60% {
transform: translate(-0.5rem, -0.04rem) rotate(-2deg) scale(1.95);
}
70% {
transform: translate(0.06rem, 0.02rem) rotate(1.25deg) scale(2.05);
}
80% {
transform: translate(-0.01rem, -0.03rem) rotate(-3deg) scale(2);
}
90% {
transform: translate(0.02rem, 0.07rem) rotate(0.5deg) scale(2.15);
}
100% {
transform: translate(0rem, 0rem) rotate(0deg) scale(2);
}
}
@keyframes rainbow {
0% {
color: #ff6b6b;
@@ -141,6 +177,14 @@
animation: 20s ease-in-out infinite balloon;
}
.balloon2 {
animation: 19s ease-in-out infinite balloon2;
}
.rainbow {
animation: 10s ease-in-out infinite rainbow;
}
a.modrinth {
color: #1bd96a;
}
+2 -3
View File
@@ -124,7 +124,6 @@ Here is a quick table showing the jar file name with the platforms it is made fo
| Jar file name | Platforms |
|-------------------------------------------------------------------------------------|-----------------------|
| `AdvancedServerList-Paper-{version}.jar`{ data-md-component="plugin-version" } | Paper |
| `AdvancedServerList-BungeeCord-{version}.jar`{ data-md-component="plugin-version" } | BungeeCord, Waterfall |
| `AdvancedServerList-Velocity-{version}.jar`{ data-md-component="plugin-version" } | Velocity |
After you added it to your plugins folder - alongside any other dependency you may want - (re)start your server or proxy to enable the plugin.
@@ -473,7 +472,7 @@ faviconCacheTime: 1
#
# Setting any not listed option or leaving this blank/removing it sets the option to resize.
#
faviconStrategy: 'resize'
faviconResizeStrategy: 'resize'
#
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
@@ -543,7 +542,7 @@ 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.
#
configVersion: 9
configVersion: 10
```
///
+3 -3
View File
@@ -78,7 +78,7 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.7-R0.1-SNAPSHOT</version>
<version>[26.1.2.build,)</version>
<scope>provided</scope>
</dependency>
@@ -94,13 +94,13 @@
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.12.2</version>
<version>2.12.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.viaversion</groupId>
<artifactId>viaversion-api</artifactId>
<version>5.7.2</version>
<version>5.12.0</version>
<scope>provided</scope>
</dependency>
@@ -3,6 +3,7 @@ package ch.andre601.advancedserverlist.paper.dialogs;
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.commands.CmdProfiles;
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
@@ -77,26 +78,26 @@ public class PaperDialog implements IDialog<Dialog>{
}
private void handle(Audience audience, DialogResponseView view, ServerListProfile slp, int profilesPosition){
Float priority = view.getFloat("priority");
String condition = view.getText("condition");
Float priority = view.getFloat(CmdProfiles.ProfileOption.PRIORITY.toDialogKey());
String condition = view.getText(CmdProfiles.ProfileOption.CONDITION.toDialogKey());
String motd = view.getText("motd");
String favicon = view.getText("favicon");
String motd = view.getText(CmdProfiles.ProfileOption.MOTD.toDialogKey());
String favicon = view.getText(CmdProfiles.ProfileOption.FAVICON.toDialogKey());
NullBool hidePlayers = NullBool.resolve(view.getBoolean("hidePlayers"));
NullBool hidePlayersHover = NullBool.resolve(view.getBoolean("hidePlayersHover"));
NullBool hidePlayers = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_HIDEPLAYERS.toDialogKey()));
NullBool hidePlayersHover = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_HIDEPLAYERSHOVER.toDialogKey()));
String hover = view.getText("hover");
String playerCountText = view.getText("text");
String hover = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_HOVER.toDialogKey());
String playerCountText = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_TEXT.toDialogKey());
NullBool extraPlayersEnabled = NullBool.resolve(view.getBoolean("extraPlayersEnabled"));
String extraPlayersCount = view.getText("extraPlayersCount");
NullBool extraPlayersEnabled = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_ENABLED.toDialogKey()));
String extraPlayersCount = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_AMOUNT.toDialogKey());
NullBool maxPlayersEnabled = NullBool.resolve(view.getBoolean("maxPlayersEnabled"));
String maxPlayersCount = view.getText("maxPlayersCount");
NullBool maxPlayersEnabled = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_MAXPLAYERS_ENABLED.toDialogKey()));
String maxPlayersCount = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_MAXPLAYERS_AMOUNT.toDialogKey());
NullBool onlinePlayersEnabled = NullBool.resolve(view.getBoolean("onlinePlayersEnabled"));
String onlinePlayersCount = view.getText("onlinePlayersCount");
NullBool onlinePlayersEnabled = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_ENABLED.toDialogKey()));
String onlinePlayersCount = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_AMOUNT.toDialogKey());
ProfileEntry.Builder builder = ProfileEntry.empty().builder();
if(motd != null && !motd.isEmpty())
@@ -181,8 +182,8 @@ public class PaperDialog implements IDialog<Dialog>{
}
@Override
public PaperDialogBuilder appendTextInput(String key, String title, String initValue, int maxLength){
this.inputs.add(DialogInput.text(key, Component.text(title))
public PaperDialogBuilder appendTextInput(CmdProfiles.ProfileOption option, String title, String initValue, int maxLength){
this.inputs.add(DialogInput.text(option.toDialogKey(), Component.text(title))
.initial(initValue == null ? "" : initValue)
.maxLength(maxLength)
.build()
@@ -191,8 +192,8 @@ public class PaperDialog implements IDialog<Dialog>{
}
@Override
public PaperDialogBuilder appendTextbox(String key, String title, List<String> initValue, int maxLength, int rows){
this.inputs.add(DialogInput.text(key, Component.text(title))
public PaperDialogBuilder appendTextbox(CmdProfiles.ProfileOption option, String title, List<String> initValue, int maxLength, int rows){
this.inputs.add(DialogInput.text(option.toDialogKey(), Component.text(title))
.initial(initValue == null ? "" : String.join("\n", initValue))
.maxLength(maxLength)
.multiline(TextDialogInput.MultilineOptions.create(rows, null))
@@ -202,11 +203,11 @@ public class PaperDialog implements IDialog<Dialog>{
}
@Override
public PaperDialogBuilder appendNumberRange(String key, String title, int initValue){
public PaperDialogBuilder appendNumberRange(CmdProfiles.ProfileOption option, String title, int initValue){
float minValue = Math.min((float)initValue, -100.0F);
float maxValue = Math.max((float)initValue, 100.0F);
this.inputs.add(DialogInput.numberRange(key, Component.text(title), minValue, maxValue)
this.inputs.add(DialogInput.numberRange(option.toDialogKey(), Component.text(title), minValue, maxValue)
.step(1.0F)
.initial((float)initValue)
.build()
@@ -215,8 +216,8 @@ public class PaperDialog implements IDialog<Dialog>{
}
@Override
public PaperDialogBuilder appendBoolean(String key, String title, NullBool initValue){
this.inputs.add(DialogInput.bool(key, Component.text(title))
public PaperDialogBuilder appendBoolean(CmdProfiles.ProfileOption option, String title, NullBool initValue){
this.inputs.add(DialogInput.bool(option.toDialogKey(), Component.text(title))
.initial(initValue.getOrDefault(false))
.build()
);
@@ -35,11 +35,9 @@ import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.paper.PaperCore;
import ch.andre601.advancedserverlist.paper.objects.FakePlayerProfile;
import ch.andre601.advancedserverlist.paper.objects.impl.PaperPlayerImpl;
import ch.andre601.advancedserverlist.paper.objects.impl.PaperServerImpl;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
import com.destroystokyo.paper.profile.PlayerProfile;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
@@ -101,8 +99,7 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent$ListedPlayerInfo");
setListedPlayers(lines, player, server);
}catch(ClassNotFoundException ex){
// Version before latest 1.20.6 builds(?)
setPlayerSample(lines, player, server);
plugin.pluginLogger().warn("playerCount -> hover is not supported on this Paper Version!");
}
}
@@ -112,7 +109,7 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent$ListedPlayerInfo");
clearListedPlayers();
}catch(ClassNotFoundException ex){
clearPlayerSample();
plugin.pluginLogger().warn("playerCount -> hidePlayers is not supported on this Paper Version!");
}
}
@@ -206,19 +203,6 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
event.getListedPlayers().addAll(playerList);
}
@SuppressWarnings({"Deprecation", "removal"})
private void clearPlayerSample(){
event.getPlayerSample().clear();
}
@SuppressWarnings({"Deprecation", "removal"})
private void setPlayerSample(List<String> lines, PaperPlayerImpl player, GenericServer server){
clearPlayerSample();
List<PlayerProfile> playerProfiles = getPlayerList(lines, player, server, FakePlayerProfile::create);
event.getPlayerSample().addAll(playerProfiles);
}
private <T> List<T> getPlayerList(List<String> lines, PaperPlayerImpl player, GenericServer server, Function<String, T> function){
List<T> playerList = new ArrayList<>(lines.size());
for(String line : lines){
@@ -1,208 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.paper.objects;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.destroystokyo.paper.profile.ProfileProperty;
import org.bukkit.profile.PlayerTextures;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.URL;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public record FakePlayerProfile(String name, UUID uuid) implements PlayerProfile{
public static FakePlayerProfile create(String name){
return new FakePlayerProfile(name, UUID.randomUUID());
}
@Override
public @Nullable UUID getUniqueId(){
return uuid();
}
@Override
public @Nullable String getName(){
return name();
}
@SuppressWarnings("removal")
@Override
public @NotNull String setName(@Nullable String name){
return name;
}
@Override
public @Nullable UUID getId(){
return null;
}
@SuppressWarnings("removal")
@Override
public @Nullable UUID setId(@Nullable UUID uuid){
return null;
}
@Override
public @NotNull PlayerTextures getTextures(){
return new FakePlayerTextures();
}
@Override
public void setTextures(@Nullable PlayerTextures textures){
}
@Override
public @NotNull Set<ProfileProperty> getProperties(){
return Collections.emptySet();
}
@Override
public boolean hasProperty(@Nullable String property){
return false;
}
@Override
public void setProperty(@NotNull ProfileProperty property){
}
@Override
public void setProperties(@NotNull Collection<ProfileProperty> properties){
}
@Override
public boolean removeProperty(@Nullable String property){
return false;
}
@Override
public void clearProperties(){
}
@Override
public boolean isComplete(){
return false;
}
@Override
public boolean completeFromCache(){
return false;
}
@Override
public boolean completeFromCache(boolean onlineMode){
return false;
}
@Override
public boolean completeFromCache(boolean lookupUUID, boolean onlineMode){
return false;
}
@Override
public boolean complete(boolean textures){
return false;
}
@Override
public boolean complete(boolean textures, boolean onlineMode){
return false;
}
@Override
public @NotNull CompletableFuture<PlayerProfile> update(){
return null;
}
@Override
public org.bukkit.profile.@NotNull PlayerProfile clone(){
return null;
}
@Override
public @NotNull Map<String, Object> serialize(){
return Collections.emptyMap();
}
private record FakePlayerTextures() implements PlayerTextures{
@Override
public boolean isEmpty(){
return false;
}
@Override
public void clear(){
}
@Override
public @Nullable URL getSkin(){
return null;
}
@Override
public void setSkin(@Nullable URL skinUrl){
}
@Override
public void setSkin(@Nullable URL skinUrl, @Nullable SkinModel skinModel){
}
@Override
public @NotNull SkinModel getSkinModel(){
return SkinModel.CLASSIC;
}
@Override
public @Nullable URL getCape(){
return null;
}
@Override
public void setCape(@Nullable URL capeUrl){
}
@Override
public long getTimestamp(){
return 0;
}
@Override
public boolean isSigned(){
return false;
}
}
}
@@ -41,7 +41,7 @@ import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NonNull;
import java.util.Collections;
import java.util.List;
@@ -58,17 +58,17 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
}
@Override
public @NotNull String getIdentifier(){
public @NonNull String getIdentifier(){
return "asl";
}
@Override
public @NotNull String getAuthor(){
public @NonNull String getAuthor(){
return "Andre601";
}
@Override
public @NotNull String getVersion(){
public @NonNull String getVersion(){
return plugin.core().version();
}
@@ -78,7 +78,7 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
}
@Override
public String onPlaceholderRequest(Player pl, @NotNull String identifier){
public String onPlaceholderRequest(Player pl, @NonNull String identifier){
String host = pl.getVirtualHost() == null ? null : pl.getVirtualHost().getHostString();
CachedPlayer cached = plugin.core().playerHandler().getCachedPlayer(pl.getUniqueId());
+10 -11
View File
@@ -41,24 +41,24 @@
<project.build.build_id/>
<plugin.version>5.7.3</plugin.version>
<plugin.version>5.9.1</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<api.version>4.1.1</api.version>
<!-- Adventure versions -->
<dependency.adventure-api>4.26.1</dependency.adventure-api>
<dependency.adventure-text-minimessage>4.26.1</dependency.adventure-text-minimessage>
<dependency.adventure-text-serializer-legacy>4.26.1</dependency.adventure-text-serializer-legacy>
<dependency.adventure-api>5.2.0</dependency.adventure-api>
<dependency.adventure-text-minimessage>5.2.0</dependency.adventure-text-minimessage>
<dependency.adventure-text-serializer-legacy>5.2.0</dependency.adventure-text-serializer-legacy>
<dependency.adventure-platform-bungeecord>4.4.1</dependency.adventure-platform-bungeecord>
<!-- Configurate version -->
<dependency.configurate-yaml>4.2.0</dependency.configurate-yaml>
<!-- Cloud versions -->
<dependency.cloud-annotations>2.0.0</dependency.cloud-annotations>
<dependency.cloud-bungee>2.0.0-beta.14</dependency.cloud-bungee>
<dependency.cloud-paper>2.0.0-beta.14</dependency.cloud-paper>
<dependency.cloud-velocity>2.0.0-beta.14</dependency.cloud-velocity>
<dependency.cloud-minecraft-extras>2.0.0-beta.14</dependency.cloud-minecraft-extras>
<dependency.cloud-annotations>2.1.0</dependency.cloud-annotations>
<dependency.cloud-bungee>2.0.0-beta.17</dependency.cloud-bungee>
<dependency.cloud-paper>2.0.1</dependency.cloud-paper>
<dependency.cloud-velocity>2.0.1</dependency.cloud-velocity>
<dependency.cloud-minecraft-extras>2.0.1</dependency.cloud-minecraft-extras>
</properties>
<profiles>
@@ -96,7 +96,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<version>3.16.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
@@ -109,7 +109,6 @@
<modules>
<module>core</module>
<module>bungeecord</module>
<module>paper</module>
<module>velocity</module>
<module>version-uploader</module>
+3 -3
View File
@@ -1,7 +1,7 @@
properdocs==1.6.6
mkdocs-material==9.7.6
properdocs==1.6.7
mkdocs-material==9.7.7
mkdocs-glightbox==0.5.2
mkdocs-redirects==1.2.2
mkdocs-redirects==1.2.3
git+https://github.com/Andre601/mkdocs-pagenav-generator
mkdocs-macros-plugin==1.5.0
pygments-minimessage==1.0.0
+1 -1
View File
@@ -73,7 +73,7 @@
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>3.4.0</version>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
+6 -6
View File
@@ -46,25 +46,25 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.2</version>
<version>2.14.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.32</version>
<version>1.6.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.6</version>
<version>5.6.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-jvm</artifactId>
<version>5.3.2</version>
<version>5.5.0</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -93,7 +93,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<version>3.16.0</version>
<configuration>
<release>16</release>
</configuration>
@@ -101,7 +101,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.0</version>
<version>3.5.1</version>
<configuration>
<archive>
<manifest>
@@ -38,15 +38,6 @@ public enum PlatformInfo{
),
List.of("Paper", "Folia")
),
BUNGEECORD(
"bungeecord",
List.of(
"bungeecord/target/AdvancedServerList-BungeeCord-{{version}}.jar",
"addons/banplugins/target/AdvancedServerList-BanPlugins-Addon-{{version}}.jar",
"addons/luckperms/target/AdvancedServerList-Luckperms-Addon-{{version}}.jar"
),
List.of("BungeeCord", "Waterfall")
),
VELOCITY(
"velocity",
List.of(
@@ -28,17 +28,15 @@ package ch.andre601.advancedserverlist.versionuploader;
import java.util.ArrayList;
import java.util.List;
public class ReleaseHolder{
public record ReleaseHolder(List<ReleaseInfo> releases){
private final List<ReleaseInfo> releases = new ArrayList<>();
public static ReleaseHolder create(){
return new ReleaseHolder(new ArrayList<>());
}
public void addRelease(String type, String platform, String url){
releases.add(new ReleaseInfo(type, platform, url));
}
public List<ReleaseInfo> getReleases(){
return releases;
}
public record ReleaseInfo(String type, String platform, String url){}
}
@@ -53,7 +53,28 @@ public class VersionUploader{
if(args.length == 0){
LOGGER.warn("MISSING ARGUMENT!");
LOGGER.warn("Usage: java -jar VersionUploader.jar <--help | --all | --modrinth | --hangar> [--dryrun]");
LOGGER.warn("Usage: java -jar VersionUploader.jar <help|upload <platform> [--dryrun]>");
System.exit(1);
return;
}
if(args[0].equalsIgnoreCase("help")){
LOGGER.info("Usage: java -jar VersionUploader.jar <command>");
LOGGER.info("");
LOGGER.info("Commands:");
LOGGER.info(" help Prints this help page and exits.");
LOGGER.info(" upload <platform> [--dryrun] Uploads to the specified platform.");
LOGGER.info("");
LOGGER.info("Upload Arguments:");
LOGGER.info(" <platform> The platforms to upload to. Allowed are all, modrinth and hangar.");
LOGGER.info(" --dryrun Do not upload and instead print the generated JSON.");
System.exit(0);
return;
}
if(!args[0].equalsIgnoreCase("upload")){
LOGGER.warn("Unknown command {}.", args[0]);
LOGGER.warn("Use 'java -jar VersionUploader.jar help' for available commands.");
System.exit(1);
return;
}
@@ -67,37 +88,22 @@ public class VersionUploader{
}
boolean dryrun = false;
if(args.length >= 2){
dryrun = args[1].equalsIgnoreCase("--dryrun");
if(args.length >= 3){
dryrun = args[2].equalsIgnoreCase("--dryrun");
}
CompletableFuture<?> future;
ReleaseHolder releaseHolder = new ReleaseHolder();
switch(args[0].toLowerCase(Locale.ROOT)){
case "--modrinth" -> future = new ModrinthVersionUploader().performUpload(release, releaseHolder, dryrun);
case "--hangar" -> future = new HangarVersionUploader().performUpload(release, releaseHolder, dryrun);
case "--all" -> future = CompletableFuture.allOf(
ReleaseHolder releaseHolder = ReleaseHolder.create();
switch(args[1].toLowerCase(Locale.ROOT)){
case "modrinth" -> future = new ModrinthVersionUploader().performUpload(release, releaseHolder, dryrun);
case "hangar" -> future = new HangarVersionUploader().performUpload(release, releaseHolder, dryrun);
case "all" -> future = CompletableFuture.allOf(
new ModrinthVersionUploader().performUpload(release, releaseHolder, dryrun),
new HangarVersionUploader().performUpload(release, releaseHolder, dryrun)
);
case "--help" -> {
LOGGER.info("Usage: java -jar VersionUploader.jar <command> [args]");
LOGGER.info("");
LOGGER.info("Commands:");
LOGGER.info(" --help Prints this help page and exits.");
LOGGER.info(" --all Performs an upload to all sites.");
LOGGER.info(" --modrinth Performs an upload to Modrinth.");
LOGGER.info(" --hangar Performs an upload to Hangar.");
LOGGER.info("");
LOGGER.info("Arguments:");
LOGGER.info(" --dryrun Prints the JSON in console while not uploading to any platform.");
LOGGER.info("");
System.exit(0);
return;
}
default -> {
LOGGER.warn("Unknown argument '{}' provided.", args[0]);
LOGGER.warn("Usage: java -jar VersionUploader.jar <--help | --all | --modrinth | --hangar> [--dryrun]");
LOGGER.warn("Unknown argument '{}' provided.", args[1]);
LOGGER.warn("Usage: java -jar VersionUploader.jar upload <all|hangar|modrinth> [--dryrun]");
System.exit(1);
return;
}
@@ -121,7 +127,7 @@ public class VersionUploader{
System.exit(1);
}
if(releaseHolder.getReleases().isEmpty()){
if(releaseHolder.releases().isEmpty()){
LOGGER.warn("No releases to share on Discord... Skipping.");
return;
}
@@ -147,7 +153,7 @@ public class VersionUploader{
StringJoiner modrinthText = new StringJoiner("\n");
String hangarText = null;
for(ReleaseHolder.ReleaseInfo info : releaseHolder.getReleases()){
for(ReleaseHolder.ReleaseInfo info : releaseHolder.releases()){
String text = String.format("[%s](%s)", info.platform(), info.url());
if(info.type().equalsIgnoreCase("modrinth")){
@@ -95,7 +95,6 @@ public class HangarVersionUploader{
final List<Path> filePaths = List.of(
new File(PlatformInfo.PAPER.getFilePaths().get(0).replace("{{version}}", pluginVersion)).toPath(),
new File(PlatformInfo.BUNGEECORD.getFilePaths().get(0).replace("{{version}}", pluginVersion)).toPath(),
new File(PlatformInfo.VELOCITY.getFilePaths().get(0).replace("{{version}}", pluginVersion)).toPath()
);
@@ -105,11 +104,6 @@ public class HangarVersionUploader{
Dependency.fromNamespace("PlaceholderAPI", false),
Dependency.fromUrl("ServerListPlus", "https://github.com/Minecrell/ServerListPlus", false)
);
final List<Dependency> bungeeDependencies = List.of(
Dependency.fromNamespace("PapiProxyBridge", false),
Dependency.fromNamespace("Maintenance", false),
Dependency.fromUrl("ServerListPlus", "https://github.com/Minecrell/ServerListPlus", false)
);
final List<Dependency> velocityDependencies = List.of(
Dependency.fromNamespace("PapiProxyBridge", false),
Dependency.fromNamespace("Maintenance", false),
@@ -118,7 +112,6 @@ public class HangarVersionUploader{
final List<MultipartObject> fileInfo = List.of(
new MultipartObject(Collections.singletonList(Platform.PAPER), null),
new MultipartObject(Collections.singletonList(Platform.WATERFALL), null),
new MultipartObject(Collections.singletonList(Platform.VELOCITY), null)
);
@@ -126,12 +119,10 @@ public class HangarVersionUploader{
releaseVersion,
Map.of(
Platform.PAPER, paperDependencies,
Platform.WATERFALL, bungeeDependencies,
Platform.VELOCITY, velocityDependencies
),
Map.of(
Platform.PAPER, List.of("1.20.6", "1.21.x"),
Platform.WATERFALL, List.of("1.19.x", "1.20.x", "1.21"),
Platform.PAPER, List.of("1.20.6", "1.21.x", "26.1.x", "26.2"),
Platform.VELOCITY, List.of("3.2", "3.3", "3.4")
),
changelog.replaceAll("\r\n", "\n"),
@@ -27,6 +27,5 @@ package ch.andre601.advancedserverlist.versionuploader.hangar.version;
public enum Platform{
PAPER,
WATERFALL,
VELOCITY
}
@@ -50,16 +50,19 @@ public class ModrinthVersionUploader{
private final List<PlatformInfo> platforms = List.of(
PlatformInfo.PAPER,
PlatformInfo.BUNGEECORD,
PlatformInfo.VELOCITY
);
private final List<String> paperVersions = List.of(
"1.20.6",
"1.21", "1.21.1", "1.21.2", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.9", "1.21.10", "1.21.11"
"1.21", "1.21.1", "1.21.2", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11",
"26.1", "26.1.1", "26.1.2",
"26.2"
);
private final List<String> versions = List.of(
"1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6",
"1.21", "1.21.1", "1.21.2", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.9", "1.21.10", "1.21.11"
"1.21", "1.21.1", "1.21.2", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11",
"26.1", "26.1.1", "26.1.2",
"26.2"
);
private final ModrinthAPI api;
@@ -94,10 +97,6 @@ public class ModrinthVersionUploader{
new ProjectVersion.ProjectDependency(null, "P1OZGk5p", null, ProjectVersion.ProjectDependencyType.OPTIONAL), // ViaVersion
new ProjectVersion.ProjectDependency(null, "HQyibRsN", null, ProjectVersion.ProjectDependencyType.OPTIONAL) // MiniPlaceholders
);
List<ProjectVersion.ProjectDependency> bungeeDependencies = List.of(
new ProjectVersion.ProjectDependency(null, "VCAqN1ln", null, ProjectVersion.ProjectDependencyType.OPTIONAL), // Maintenance
new ProjectVersion.ProjectDependency(null, "bEIUEGTX", null, ProjectVersion.ProjectDependencyType.OPTIONAL) // PAPIProxyBridge
);
List<ProjectVersion.ProjectDependency> velocityDependencies = List.of(
new ProjectVersion.ProjectDependency(null, "VCAqN1ln", null, ProjectVersion.ProjectDependencyType.OPTIONAL), // Maintenance
new ProjectVersion.ProjectDependency(null, "bEIUEGTX", null, ProjectVersion.ProjectDependencyType.OPTIONAL), // PAPIProxyBridge
@@ -126,7 +125,6 @@ public class ModrinthVersionUploader{
switch(platformInfo){
case PAPER -> builder.dependencies(paperDependencies);
case BUNGEECORD -> builder.dependencies(bungeeDependencies);
case VELOCITY -> builder.dependencies(velocityDependencies);
}