Compare commits

...
74 Commits
Author SHA1 Message Date
Andre601 bcd5e77166 Try new Bungeecord version to fix CI 2025-01-05 22:02:30 +01:00
Andre601 5d2fa03601 Upload hover examples 2025-01-05 20:39:54 +00:00
Andre601 8f1a5e5a37 Add option to hide online players list. 2025-01-05 20:19:57 +01:00
Andre601 05fde902a4 Merge pull request 'Update dependency space.arim.libertybans:bans-api to v1.1.0-SNAPSHOT' (#395) from renovate/all-minor-patch into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/395
2025-01-04 12:18:43 +00:00
Andre601's Bot d69e70c485 Update dependency space.arim.libertybans:bans-api to v1.1.0-SNAPSHOT 2025-01-04 12:16:35 +00:00
Andre601 fba1e84171 Disable dependency Dashboard 2025-01-04 12:15:36 +00:00
Andre601 530f0fd954 Update renovate.json with some automerge and grouping stuff. 2025-01-03 16:06:13 +00:00
Andre601 8bec42bb91 Fix wrong Paper repo URL for renovate 2025-01-03 02:38:41 +00:00
Andre601 94982ff1e8 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.2.1' (#394) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/394
2025-01-02 13:29:51 +00:00
Andre601's Bot 1f9795ed97 Update dependency com.viaversion:viaversion-api to v5.2.1 2025-01-02 12:01:33 +00:00
Andre601 c6f95cb78a Update formatting.md 2024-12-30 13:48:48 +01:00
Andre601 571f9f6b38 Add support for SayanVanish 2024-12-29 01:24:55 +01:00
Andre601 6d7fbb8c25 Merge pull request 'Update API reference' (#393) from feature/update-api-reference into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/393
2024-12-25 00:58:11 +00:00
Andre601 d3d83e5e11 Update ProfileEntry index page 2024-12-25 00:46:43 +00:00
Andre601 82fb9c90f4 Update API reference 2024-12-25 00:39:03 +00:00
Andre601 6841a5a6e0 Undo componentlogger changes on velocity 2024-12-24 22:27:26 +01:00
Andre601 6f41cd4e3a Use a fallback logger for velocity versions without ComponentLoggers 2024-12-24 22:05:56 +01:00
Andre601 379f36832e Use snippet links 2024-12-24 21:45:01 +01:00
Andre601 5d8a39cd22 Update config example in getting-started 2024-12-24 21:43:39 +01:00
Andre601 9dba820840 Reduce flood of messages on Startup + make ASL banner hidable.
(I really don't get why people get upset about a few lines of text... Won't make the Log file like 10GB bigger or smth...)
2024-12-24 21:41:39 +01:00
Andre601 58712ca5c5 Merge pull request 'Update dependency net.kyori:adventure-text-serializer-legacy to v4.18.0' (#392) from renovate/dependency.adventure-text-serializer-legacy into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/392
2024-12-24 12:04:13 +00:00
Andre601's Bot e19e942799 Update dependency net.kyori:adventure-text-serializer-legacy to v4.18.0 2024-12-24 12:01:21 +00:00
Andre601 03434130c4 Update dependency net.kyori:adventure-text-minimessage to v4.18.0 2024-12-23 13:20:48 +01:00
Andre601 99df25551a Merge pull request 'Update dependency net.kyori:adventure-api to v4.18.0' (#390) from renovate/dependency.adventure-api into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/390
2024-12-23 12:14:32 +00:00
Andre601's Bot 4f31e4ce6f Update dependency net.kyori:adventure-api to v4.18.0 2024-12-23 12:01:35 +00:00
Andre601 ba097c538d Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.15' (#389) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/389
2024-12-22 13:03:31 +00:00
Andre601's Bot aa52435591 Update dependency ch.qos.logback:logback-classic to v1.5.15 2024-12-22 12:01:59 +00:00
Andre601 f44194d24f Update docs 2024-12-21 02:21:33 +01:00
Andre601 0e2d760ea6 Upload center_text_example.jpg 2024-12-20 13:31:42 +00:00
Andre601 c1e7e6b3ff Merge pull request 'Add support for centering MOTD lines' (#388) from feature/motd-center-feature into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/388
2024-12-20 13:24:41 +00:00
Andre601 96d383a5a1 Merge branch 'master' into feature/motd-center-feature 2024-12-20 13:24:11 +00:00
Andre601 79ba7877bf Bump version and add docs 2024-12-20 13:46:53 +01:00
Andre601 86b9aaa7c6 Add support for centering MOTD lines 2024-12-20 13:40:11 +01:00
Andre601 0cb3c036af Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.14' (#387) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/387
2024-12-20 12:11:41 +00:00
Andre601's Bot b1f7b75e2d Update dependency ch.qos.logback:logback-classic to v1.5.14 2024-12-20 12:01:15 +00:00
Andre601 e9bc72c165 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.13' (#386) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/386
2024-12-19 12:02:24 +00:00
Andre601's Bot 93203249fe Update dependency ch.qos.logback:logback-classic to v1.5.13 2024-12-19 12:01:11 +00:00
Andre601 2523ccb425 Merge pull request 'Update dependency com.google.guava:guava to v33.4.0-jre' (#384) from renovate/com.google.guava-guava-33.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/384
2024-12-17 12:04:55 +00:00
Andre601 94972dad31 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.4' (#383) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/383
2024-12-17 12:04:39 +00:00
Andre601's Bot f8ac310259 Update dependency com.google.guava:guava to v33.4.0-jre 2024-12-17 12:01:48 +00:00
Andre601's Bot 5d8f5d81ed Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.4 2024-12-17 12:01:40 +00:00
Andre601 3111d7933d Merge pull request 'Move Migration pages to sub-pages' (#382) from docs/move-migration-pages into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/382
2024-12-16 21:42:31 +00:00
Andre601 55f7e17d34 Fix typo. 2024-12-16 21:42:14 +00:00
Andre601 0e88a50deb Move Migration pages to sub-pages 2024-12-16 22:38:55 +01:00
Andre601 83f351de6d Try github.run_number variable 2024-12-16 19:42:19 +00:00
Andre601 b96d1cb1a9 Merge pull request 'Update dependency mkdocs-material to v9.5.49' (#381) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/381
2024-12-16 12:04:47 +00:00
Andre601's Bot 517ff1df82 Update dependency mkdocs-material to v9.5.49 2024-12-16 12:01:18 +00:00
Andre601 e8c7c4ee18 Merge pull request 'Update Wiki Announcement' (#380) from feature/wiki-update-announcement into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/380
2024-12-13 14:15:21 +00:00
Andre601 da44eac70e Fix typos 2024-12-13 14:05:41 +00:00
Andre601 e85c121ee4 Add missing .svg 2024-12-13 13:58:10 +00:00
Andre601 0c175999fc Update announcement 2024-12-13 13:57:32 +00:00
Andre601 9c3f237f6d Use ruby for hocon highlighting 2024-12-11 20:42:52 +01:00
Andre601 777545c94f Possible fix for IndexOutOfBoundsException in condition parsing. 2024-12-10 23:22:41 +01:00
Andre601 dd197609e1 Set secrets via ENV (secrets is deprecated) 2024-12-10 13:29:13 +00:00
Andre601 14ee306463 Bump version 2024-12-10 14:09:34 +01:00
Andre601 a635aa8c91 Merge pull request 'Update dependency net.william278:papiproxybridge to v1.7.2' (#379) from renovate/net.william278-papiproxybridge-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/379
2024-12-09 12:05:22 +00:00
Andre601 050ac3262a Merge pull request 'Update dependency mkdocs-material to v9.5.48' (#378) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/378
2024-12-09 12:05:12 +00:00
Andre601's Bot 89aa309c90 Update dependency net.william278:papiproxybridge to v1.7.2 2024-12-09 12:02:16 +00:00
Andre601's Bot e9b004c3f2 Update dependency mkdocs-material to v9.5.48 2024-12-09 12:02:05 +00:00
Andre601 3ecca64a3d Allow random to be converted in MiniMOTDConfigMigrator 2024-12-09 03:04:22 +01:00
Andre601 96dcea4e5b Fix admonition box 2024-12-08 13:54:35 +00:00
Andre601 400f4709f5 Add missing ! 2024-12-08 13:52:30 +00:00
Andre601 5d4307128b Use thumbnail + link for better privacy 2024-12-08 13:51:44 +00:00
Andre601 65c96690f6 Use youtube-nocookie domain for iframes 2024-12-08 13:44:04 +00:00
Andre601 483d582cd1 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.2.0' (#377) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/377
2024-12-07 12:02:00 +00:00
Andre601's Bot 6f14e17ae7 Update dependency com.viaversion:viaversion-api to v5.2.0 2024-12-07 12:01:26 +00:00
Andre601 ff32cc1005 Use annotation and (hopefully) improve JS code) 2024-12-07 02:03:29 +01:00
Andre601 bcc18d7738 [Wiki] Add tutorials page 2024-12-05 23:51:20 +01:00
Andre601 629079b438 Remove container image (Is now default) 2024-12-05 01:40:04 +00:00
Andre601 bce03b68a8 Remove container image (Is now default) 2024-12-05 01:39:50 +00:00
Andre601 841c32de0d Update docs and smaller corrections 2024-12-04 23:10:50 +01:00
Andre601 f321ef0162 [Wiki] Add info about favicon creation. 2024-12-04 16:42:51 +00:00
Andre601 eca32d1858 Add video of KasaiSora 2024-12-04 16:26:40 +00:00
Andre601 f2c1f6e491 Update favicons description 2024-12-04 16:19:57 +00:00
84 changed files with 1163 additions and 521 deletions

No files matched your search

-2
View File
@@ -16,8 +16,6 @@ on:
jobs:
deployWiki:
runs-on: codeberg-tiny
container:
image: ghcr.io/catthehacker/ubuntu:act-latest
steps:
- name: "Checkout Source Repository"
uses: https://code.forgejo.org/actions/checkout@v4
+6 -7
View File
@@ -16,12 +16,11 @@ on:
env:
BRANCH_NAME: "${{ github.event.repository.name }}/${{ github.event.pull_request.number }}"
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}"
jobs:
createPreview:
runs-on: codeberg-tiny
container:
image: ghcr.io/catthehacker/ubuntu:act-latest
steps:
#
# Finding and updating comment in Pull request.
@@ -93,7 +92,7 @@ jobs:
|---------|----------------------------------------------------------------------------------------------------------|
| Commit | ${{ github.event.pull_request.head.sha }} |
| Preview | https://preview.andre601.ch/@${{ github.event.repository.name }}~${{ github.event.pull_request.number }} |
| Logs | ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| Logs | ${{ env.RUN_URL }} |
comment-id: "${{ steps.comment.outputs.comment-id }}"
issue-number: "${{ github.event.pull_request.number }}"
token: "${{ secrets.BOT_TOKEN }}"
@@ -107,10 +106,10 @@ jobs:
Pull request Preview failed! Check the logs for details.
| Name | Link |
|---------|-------------------------------------------------------------------------------------|
| Commit | ${{ github.event.pull_request.head.sha }} |
| Logs | ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| Name | Link |
|---------|-------------------------------------------|
| Commit | ${{ github.event.pull_request.head.sha }} |
| Logs | ${{ RUN_URL }} |
comment-id: "${{ steps.comment.outputs.comment-id }}"
issue-number: "${{ github.event.pull_request.number }}"
token: "${{ secrets.BOT_TOKEN }}"
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+7 -5
View File
@@ -5,20 +5,22 @@ when:
steps:
- name: "Build Jar and Upload"
image: maven:3.9.9-eclipse-temurin-21
secrets:
- modrinth_api_token
- hangar_api_token
- discord_webhook_url
environment:
CODEBERG_API_TOKEN:
from_secret: cb_token
MODRINTH_API_TOKEN:
from_secret: modrinth_api_token
HANGAR_API_TOKEN:
from_secret: hangar_api_token
DISCORD_WEBHOOK_URL:
from_secret: discord_webhook_url
commands:
- mvn clean install
- cd version-uploader/target
- mv VersionUploader.jar ../../
- cd ../../
- java -jar VersionUploader.jar --all
- name: "Upload Jars to Codeber"
- name: "Upload Jars to Codeberg"
image: woodpeckerci/plugin-gitea-release
settings:
base_url: https://codeberg.org
+3
View File
@@ -86,6 +86,9 @@ Below can you find a collection of videos made for my plugin. If you made a vide
<details><summary>Click to show/hide Videos</summary>
<p>
English Video by KasaiSora
[![video thumbnail](https://img.youtube.com/vi/9cU0uUWHOO0/0.jpg)](https://youtube.com/watch?v=9cU0uUWHOO0)
Spanish Video by Ajneb97
[![video thumbnail](https://img.youtube.com/vi/rIbljm_4HVI/0.jpg)](https://youtube.com/watch?v=rIbljm_4HVI)
+1 -1
View File
@@ -99,7 +99,7 @@
<dependency>
<groupId>space.arim.libertybans</groupId>
<artifactId>bans-api</artifactId>
<version>1.1.0-RC1</version>
<version>1.1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
+18 -2
View File
@@ -49,6 +49,10 @@
<id>sonatype</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository>
<id>repo-sayandevelopment</id>
<url>https://repo.sayandev.org/snapshots</url>
</repository>
</repositories>
<dependencies>
@@ -69,14 +73,14 @@
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2</version>
<version>1.21-R0.1-SNAPSHOT</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2</version>
<version>1.21-R0.1-SNAPSHOT</version>
<type>javadoc</type>
<scope>provided</scope>
</dependency>
@@ -124,6 +128,18 @@
<version>2.9.0-4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-api</artifactId>
<version>1.6.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-proxy-bungeecord</artifactId>
<version>1.6.1</version>
<scope>provided</scope>
</dependency>
<!-- Other -->
<dependency>
@@ -47,6 +47,7 @@ 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.sayandev.sayanvanish.bungeecord.api.SayanVanishBungeeAPI;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
@@ -55,6 +56,7 @@ 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>{
@@ -71,12 +73,13 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
@Override
public void onLoad(){
logger.info("Loading libraries. This may take a while...");
// Using getLogger() here, because PluginLogger requires MiniMessage, which isn't loaded at this stage.
getLogger().info("Loading libraries. This may take a while...");
successfulLoad = loadLibs();
if(successfulLoad){
logger.info("Library loading completed successfully!");
getLogger().info("Library loading completed successfully!");
}else{
logger.warn("Library loading completed with errors!");
getLogger().warning("Library loading completed with errors!");
}
}
@@ -84,7 +87,7 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
public void onEnable(){
if(!successfulLoad){
logger.warn("There were issues during the plugins Loading-phase! Please see the console for possible reasons.");
logger.warn("The plugin won't be enabled to avoid problems.");
logger.warn("Aborting further enabling of the plugin to avoid errors.");
return;
}
@@ -97,11 +100,13 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
public void onDisable(){
core.disable();
getProxy().getScheduler().cancel(this);
audiences.close();
}
@Override
public void loadCommands(){
getProxy().getPluginManager().registerCommand(this, new CmdAdvancedServerList(this));
getPluginLogger().success("Registered <white>/advancedserverlist</white>!");
}
@Override
@@ -206,6 +211,9 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
// Exclude players when PremiumVanish is enabled and player is hidden.
if(getProxy().getPluginManager().getPlugin("PremiumVanish") != null){
players.removeIf(BungeeVanishAPI::isInvisible);
}else // Do the same if SayanVanish is enabled.
if(getProxy().getPluginManager().getPlugin("SayanVanish") != null){
players.removeIf(player -> SayanVanishBungeeAPI.getInstance().isVanished(player.getUniqueId()));
}
return players.size();
@@ -226,7 +234,7 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
return true;
}catch(Exception ex){
logger.warn("Encountered an Exception while trying to load dependencies.", ex);
getLogger().log(Level.WARNING, "Encountered an Exception while trying to load dependencies.", ex);
return false;
}
}
@@ -118,6 +118,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
ping.getPlayers().setSample(players);
}
@Override
public void setPlayersHidden(){
ping.getPlayers().setSample(new ServerPing.PlayerInfo[0]);
}
@Override
public void setFavicon(Favicon favicon){
ping.setFavicon(favicon);
@@ -27,6 +27,7 @@ package ch.andre601.advancedserverlist.bungeecord.logging;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -55,21 +56,21 @@ public class BungeeLogger implements PluginLogger{
@Override
public void info(String msg, Object... args){
logger.info(String.format(msg, args));
logger.info(ComponentParser.textFormatted(msg, args).toStringStriped());
}
@Override
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
logger.warning(ComponentParser.textFormatted(msg, args).toStringStriped());
}
@Override
public void warn(String msg, Throwable throwable){
logger.log(Level.WARNING, msg, throwable);
logger.log(Level.WARNING, ComponentParser.text(msg).toStringStriped(), throwable);
}
@Override
public void warn(String msg, Throwable throwable, Object... args){
logger.log(Level.WARNING, String.format(msg, args), throwable);
logger.log(Level.WARNING, ComponentParser.textFormatted(msg, args).toStringStriped(), throwable);
}
}
+17 -5
View File
@@ -41,7 +41,7 @@
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<plugin.config.version>6</plugin.config.version>
<plugin.config.version>7</plugin.config.version>
</properties>
<repositories>
@@ -77,9 +77,11 @@
<dependency>
<groupId>ch.andre601</groupId>
<artifactId>expressionparser</artifactId>
<version>1.4.3</version>
<version>1.5.0</version>
<scope>compile</scope>
</dependency>
<!-- Configuration -->
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
@@ -129,7 +131,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.3.1-jre</version>
<version>33.4.0-jre</version>
<scope>provided</scope>
</dependency>
@@ -137,7 +139,7 @@
<dependency>
<groupId>net.william278</groupId>
<artifactId>papiproxybridge</artifactId>
<version>1.7.1</version>
<version>1.7.2</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -157,7 +159,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.3</version>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -168,6 +170,16 @@
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
<excludes>
<exclude>char-widths.json.gz</exclude>
</excludes>
</resource>
<resource>
<filtering>false</filtering>
<directory>${project.basedir}/src/main/resources</directory>
<includes>
<include>char-widths.json.gz</include>
</includes>
</resource>
</resources>
<plugins>
@@ -32,6 +32,7 @@ import ch.andre601.advancedserverlist.core.commands.CommandHandler;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenancePlaceholder;
import ch.andre601.advancedserverlist.core.file.FileHandler;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.TextCenterUtil;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.advancedserverlist.core.profiles.handlers.PlayerHandler;
@@ -47,6 +48,8 @@ public class AdvancedServerList<F>{
private final FileHandler fileHandler;
private final CommandHandler commandHandler;
private final PlayerHandler playerHandler;
private final TextCenterUtil textCenterUtil;
private static final AdvancedServerListAPI api = AdvancedServerListAPI.get();
private final ProfileConditionParser parser = ProfileConditionParser.create();
@@ -59,18 +62,18 @@ public class AdvancedServerList<F>{
this.fileHandler = new FileHandler(this);
this.commandHandler = new CommandHandler(this);
this.playerHandler = new PlayerHandler(this);
this.textCenterUtil = new TextCenterUtil(this);
plugin.getPluginLogger().info("Registering internal Placeholders...");
placeholders.forEach(this::addPlaceholder);
if(plugin.isPluginEnabled("Maintenance")){
plugin.getPluginLogger().info("Found Maintenance Plugin. Registering extra Placeholder...");
addPlaceholder(new MaintenancePlaceholder(this));
}
plugin.getPluginLogger().info("Completed internal Placeholder registration!");
resolveVersion();
getPlugin().getPluginLogger().info("Starting <white>AdvancedServerList v%s</white>...", version);
load();
}
@@ -110,16 +113,20 @@ public class AdvancedServerList<F>{
return updateChecker;
}
public TextCenterUtil getTextCenterUtil(){
return textCenterUtil;
}
public void disable(){
getPlugin().getPluginLogger().info("Saving playercache.json file...");
getPlugin().getPluginLogger().info("[-] Saving <white>playercache.json</white> file...");
getPlayerHandler().save();
if(updateChecker != null){
getPlugin().getPluginLogger().info("Disabling Update Checker...");
getPlugin().getPluginLogger().info("[-] Disabling Update Checker...");
updateChecker.disable();
}
getPlugin().getPluginLogger().info("AdvancedServerList disabled!");
getPlugin().getPluginLogger().success("AdvancedServerList disabled!");
}
public void clearFaviconCache(){
@@ -131,70 +138,56 @@ public class AdvancedServerList<F>{
}
private void load(){
printBanner();
resolveVersion();
getPlugin().getPluginLogger().info("Starting AdvancedServerList v%s...", version);
getPlugin().getPluginLogger().info("Platform: %s", plugin.getPlatformInfo());
if(getFileHandler().loadConfig()){
getPlugin().getPluginLogger().info("Successfully loaded config.yml!");
}else{
getPlugin().getPluginLogger().warn("Unable to load config.yml! Check previous lines for errors.");
if(!getFileHandler().loadConfig()){
getPlugin().getPluginLogger().failure("Unable to load <white>config.yml</white>! Check previous lines for errors.");
return;
}
if(getFileHandler().isOldConfig()){
getPlugin().getPluginLogger().info("Detected old config.yml. Attempting to migrate...");
getPlugin().getPluginLogger().info("[-] Detected old <white>config.yml</white>. Attempting to migrate...");
if(getFileHandler().migrateConfig()){
getPlugin().getPluginLogger().info("Migration completed successfully!");
getPlugin().getPluginLogger().success("Migration completed successfully!");
}else{
getPlugin().getPluginLogger().warn("Couldn't migrate config.yml! Check previous lines for errors.");
getPlugin().getPluginLogger().failure("Couldn't migrate <white>config.yml</white>! Check previous lines for errors.");
return;
}
}
if(getFileHandler().getBool(true, "printBanner")){
printBanner();
}
getPlugin().getPluginLogger().info("Platform: <white>%s</white>", plugin.getPlatformInfo());
getPlugin().getPluginLogger().info("");
if(getFileHandler().loadProfiles()){
getPlugin().getPluginLogger().info("Successfully loaded %d profile(s)!", getFileHandler().getProfiles().size());
getPlugin().getPluginLogger().success("Successfully loaded <white>%d</white> profile(s)!", getFileHandler().getProfiles().size());
}else{
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
getPlugin().getPluginLogger().failure("Unable to load profiles! Check previous lines for errors.");
return;
}
getPlugin().loadFaviconHandler(this);
getPlugin().getPluginLogger().info("Loading Commands...");
plugin.loadCommands();
getPlugin().getPluginLogger().info("Commands loaded!");
getPlugin().getPluginLogger().info("Loading events...");
plugin.loadEvents();
getPlugin().getPluginLogger().info("Events loaded!");
getPlugin().getPluginLogger().info("Loading playercache.json...");
getPlayerHandler().load();
getPlugin().getPluginLogger().info("Loading bStats metrics. Disable it in the global config under /plugins/bstats/");
plugin.loadMetrics();
getPlugin().getPluginLogger().info("Metrics loaded!");
getPlugin().getPluginLogger().info("Enabling Schedulers...");
plugin.startScheduler();
getPlugin().getPluginLogger().info("Schedulers enabled.");
getPlugin().getPluginLogger().info("AdvancedServerList is ready!");
getPlugin().getPluginLogger().success("<green>AdvancedServerList is ready!");
if(getFileHandler().getBoolean("checkUpdates"))
this.updateChecker = new UpdateChecker(this);
}
private void printBanner(){
getPlugin().getPluginLogger().info(" _____ _");
getPlugin().getPluginLogger().info(" /\\ / ____| |");
getPlugin().getPluginLogger().info(" / \\ | (___ | |");
getPlugin().getPluginLogger().info(" / /\\ \\ \\___ \\| |");
getPlugin().getPluginLogger().info(" / ____ \\ ____) | |____");
getPlugin().getPluginLogger().info("/_/ \\_\\_____/|______|");
getPlugin().getPluginLogger().info("<#3b90ff> __ _______ ___");
getPlugin().getPluginLogger().info("<#3b90ff> /\\ \\ / ____|_| | |");
getPlugin().getPluginLogger().info("<#3b90ff> / \\ \\ | (_(___ | | |");
getPlugin().getPluginLogger().info("<#3b90ff> / /\\ \\ \\ \\___ \\ \\| | |");
getPlugin().getPluginLogger().info("<#3b90ff> / ____ \\ \\ ____) | | |_|____");
getPlugin().getPluginLogger().info("<#3b90ff>/_/_/ \\_\\_\\_____/_/|______|_|");
getPlugin().getPluginLogger().info("");
}
@@ -211,7 +204,6 @@ public class AdvancedServerList<F>{
}
private void addPlaceholder(PlaceholderProvider placeholderProvider){
getPlugin().getPluginLogger().info("Registering %s Placeholders...", placeholderProvider.getIdentifier());
AdvancedServerList.getApi().addPlaceholderProvider(placeholderProvider);
}
}
@@ -123,11 +123,11 @@ public class UpdateChecker{
private void startUpdateChecker(){
executor.scheduleAtFixedRate(() -> {
logger.info("Looking for an update...");
logger.info("[-] Looking for an update...");
performUpdateCheck().whenComplete((version, throwable) -> {
if(version == null || throwable != null){
logger.warn("Failed to look for any updates. Check previous messages for causes.");
logger.failure("Failed to look for any updates. Check previous messages for causes.");
return;
}
@@ -136,9 +136,9 @@ public class UpdateChecker{
int result = version.compare(core.getVersion());
switch(result){
case -1 -> printUpdateBanner(version);
case 0 -> logger.info("You are running the latest version!");
case 0 -> logger.success("You are running the latest version!");
case 1 -> logger.info(
"Your version (%s) seems to be newer than the latest release (%s). Are you running a dev build?",
"[?] Your version (<white>%s</white>) seems to be newer than the latest release (<white>%s</white>). Are you running a dev build?",
core.getVersion(), version.versionNumber()
);
}
@@ -185,18 +185,18 @@ public class UpdateChecker{
logger.warn("=======================================================================");
logger.warn("You are running an outdated version of AdvancedServerList!");
logger.warn("");
logger.warn("Your version: %s", core.getVersion());
logger.warn("Modrinth: %s", version.versionNumber());
logger.warn("Your version: <white>%s</white>", core.getVersion());
logger.warn("Modrinth: <white>%s</white>", version.versionNumber());
logger.warn("");
if(!version.isRelease()){
logger.warn("WARNING!");
logger.warn("<bold>WARNING!</bold>");
logger.warn("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
logger.warn("");
}
logger.warn("Download the latest version from here:");
logger.warn("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
logger.warn("<white>https://modrinth.com/plugin/advancedserverlist/version/%s</white>", version.id());
logger.warn("=======================================================================");
}
@@ -102,43 +102,27 @@ public class CommandHandler{
public void handle(CmdSender sender, String[] args){
sender.sendPrefixedMsg("- Commands. Hover for details.");
for(PluginCommand command : core.getCommandHandler().getSubCommands()){
sender.sendPrefixedMsg("");
sender.sendPrefixedMsg(
"<aqua><hover:show_text:\"%s\">" +
sender.sendMsg();
sender.sendMsg(
"<click:suggest_command:/asl %s>" +
"/asl <white>%s</white>" +
"</click>" +
"</hover></aqua>",
getCommandHover(command),
command.name(),
command.usage() +
"</click>",
command.name()
);
sender.sendMsg("<grey>[<hover:show_text:\"%s\"><white>Permission</white></hover>]</grey>", command.permission());
}
}
@Override
public String usage(){
return "<aqua>/asl <white>help</white></aqua>";
return new CommandStringBuilder("help", description())
.build();
}
@Override
public String description(){
return "Shows all available commands.";
}
private String getCommandHover(PluginCommand command){
return String.format(
"""
<grey>Usage: %s
Permission: <white>%s</white>
<white>%s</white>
""",
command.usage(),
command.permission(),
command.description()
);
}
}
private static class Reload extends PluginCommand{
@@ -172,7 +156,8 @@ public class CommandHandler{
@Override
public String usage(){
return "<aqua>/asl <white>reload</white></aqua>";
return new CommandStringBuilder("reload", description())
.build();
}
@Override
@@ -206,7 +191,8 @@ public class CommandHandler{
@Override
public String usage(){
return "<aqua>/asl <white>clearcache</white></aqua>";
return new CommandStringBuilder("clearcache", description())
.build();
}
@Override
@@ -268,7 +254,18 @@ public class CommandHandler{
@Override
public String usage(){
return "<aqua>/asl <white>migrate <grey>\\<</grey>Plugin<grey>></grey></white></aqua>";
return new CommandStringBuilder("migrate", description())
.appendSpace()
.appendArgument(new CommandStringBuilder.ArgumentBuilder("Plugin").description(
"""
The Plugin to migrate from.
Supported options:
- <white>ServerListPlus</white>
- <white>MiniMOTD</white>
"""
).build())
.build();
}
@Override
@@ -360,7 +357,7 @@ public class CommandHandler{
sender.sendErrorMsg("<red>There was an error while creating the file</red> %s<red>!", copy);
sender.sendErrorMsg("<red>Check console for further details.");
core.getPlugin().getPluginLogger().warn("Encountered IOException while creating file %s", ex, copy);
core.getPlugin().getPluginLogger().warn("Encountered IOException while creating file <white>%s</white>", ex, copy);
return;
}
@@ -378,7 +375,7 @@ public class CommandHandler{
sender.sendErrorMsg("<red>There was an error while loading the file</red> %s<red>!", copy);
sender.sendErrorMsg("<red>Check console for further details.");
core.getPlugin().getPluginLogger().warn("Encountered IOException while loading file %s", ex, copy);
core.getPlugin().getPluginLogger().warn("Encountered IOException while loading file <white>%s</white>", ex, copy);
return;
}
@@ -398,7 +395,7 @@ public class CommandHandler{
sender.sendErrorMsg("<red>There was an Error while copying values from</red> %s <red>to</red> %s<red>.", name, copy);
sender.sendErrorMsg("<red>Check console for details.");
core.getPlugin().getPluginLogger().warn("Encountered SerializationException while set values for %s!", ex, copy);
core.getPlugin().getPluginLogger().warn("Encountered SerializationException while set values for <white>%s</white>!", ex, copy);
return;
}
@@ -410,7 +407,7 @@ public class CommandHandler{
sender.sendErrorMsg("<red>There was an Error while trying to save</red> %s<red>!", copy);
sender.sendErrorMsg("<red>Check console for details.");
core.getPlugin().getPluginLogger().warn("Encountered IOException while saving ConfigurationNode for %s!", ex, copy);
core.getPlugin().getPluginLogger().warn("Encountered IOException while saving ConfigurationNode for <white>%s</white>!", ex, copy);
}
}
default -> {
@@ -422,11 +419,32 @@ public class CommandHandler{
@Override
public String usage(){
return "<aqua>/asl <white>profiles</white> <grey>\\<" +
"<white>add</white> \\<<white>name</white>> | " +
"<white>copy</white> \\<<white>profile</white>> \\<<white>name</white>> | " +
"<white>list</white>" +
"></grey></aqua>";
return new CommandStringBuilder("profiles", "Creates a new profile, copies one from an existing file, or lists all available profiles.")
.appendSpace()
.appendText("<grey>\\<")
// add <name>
.appendLiteralArgument("add", "Adds a new profile using the default values.")
.appendSpace()
.appendArgument(new CommandStringBuilder.ArgumentBuilder("name").description("Name of the new profile").required().build())
// Divider
.appendSpace()
.appendText("|")
.appendSpace()
// copy <profile> <name>
.appendLiteralArgument("copy", "Creates a copy of the provided profile.")
.appendSpace()
.appendArgument(new CommandStringBuilder.ArgumentBuilder("profile").description("The profile to copy.").required().build())
.appendSpace()
.appendArgument(new CommandStringBuilder.ArgumentBuilder("name").description("Name of the copy.").required().build())
// Divider
.appendSpace()
.appendText("|")
.appendSpace()
// list
.appendLiteralArgument("list", "Lists all currently know profiles and wether they are valid or not.")
// Closing bracket
.appendText("></grey>")
.build();
}
@Override
@@ -0,0 +1,110 @@
/*
* MIT License
*
* Copyright (c) 2022-2025 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package ch.andre601.advancedserverlist.core.commands;
import java.util.ArrayList;
import java.util.List;
public class CommandStringBuilder{
private final List<CommandPart> commandParts = new ArrayList<>();
public CommandStringBuilder(String subcommand, String description){
appendText("<hover:show_text:\"<grey>" + description + "</grey>\"><white>" + subcommand + "</white></hover>");
}
public CommandStringBuilder appendArgument(Argument argument){
this.commandParts.add(argument);
return this;
}
public CommandStringBuilder appendText(String text){
this.commandParts.add(new Text(text));
return this;
}
public CommandStringBuilder appendLiteralArgument(String name, String description){
return appendText("<hover:show_text:\"<grey>" + description + "</grey>\"><white>" + name + "</white></hover>");
}
public CommandStringBuilder appendSpace(){
return appendText(" ");
}
public String build(){
StringBuilder builder = new StringBuilder("<aqua>/asl ");
for(CommandPart part : commandParts){
builder.append(part.build());
}
builder.append("</aqua>"); // Closing the first color tag.
return builder.toString();
}
public static class ArgumentBuilder{
private final String name;
private String description = "No description provided.";
private boolean required = false;
public ArgumentBuilder(String name){
this.name = name;
}
public ArgumentBuilder description(String description){
this.description = description;
return this;
}
public ArgumentBuilder required(){
this.required = true;
return this;
}
public Argument build(){
return new Argument(name, description, required);
}
}
private record Text(String text) implements CommandPart{
@Override
public String build(){
return text();
}
}
private record Argument(String name, String description, boolean required) implements CommandPart{
@Override
public String build(){
return "<hover:show_text:\"<grey>" + description() + "</grey>\">" +
"<grey>" + (required() ? "\\<" : "[") + "<white>" + name() + "</white>" + (required() ? ">" : "]") +
"</grey></hover>";
}
}
private interface CommandPart{
String build();
}
}
@@ -36,6 +36,10 @@ import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import java.util.List;
public class PingEventHandler{
@@ -138,14 +142,18 @@ public class PingEventHandler{
GenericServer finalServer = event.createGenericServer(online, max, host);
if(ProfileManager.checkOption(entry.motd()) && ignoreMaintenance(event, "motd")){
logger.debug(PingEventHandler.class, "'motd' option present. Applying '%s'...", String.join("\\n", entry.motd()));
logger.debug(PingEventHandler.class, "'motd' option present. Applying ['%s']...", String.join("', '", entry.motd()));
event.setMotd(
ComponentParser.list(entry.motd())
List<Component> motd = entry.motd().stream()
.map(line -> ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.modifyText(text -> plugin.getCore().getTextCenterUtil().getCenteredText(text))
.toComponent()
);
)
.toList();
event.setMotd(Component.join(JoinConfiguration.separator(Component.newline()), motd));
}
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
@@ -167,8 +175,14 @@ public class PingEventHandler{
);
}
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && ignoreMaintenance(event, "playerCountHover")){
logger.debug(PingEventHandler.class, "'playerCount -> hover' option set. Applying '%s'...", String.join("\\n", entry.players()));
boolean hidePlayersHover = ProfileManager.checkOption(entry.hidePlayersHoverEnabled());
if(hidePlayersHover){
logger.debug(PingEventHandler.class, "'playerCount -> hidePlayersHover' option set. Hiding Player Hover...");
event.setPlayersHidden();
}
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && !hidePlayersHover && ignoreMaintenance(event, "playerCountHover")){
logger.debug(PingEventHandler.class, "'playerCount -> hover' option set. Applying ['%s']...", String.join("', '", entry.players()));
event.setPlayers(entry.players(), player, server);
}
@@ -46,7 +46,8 @@ public class ConfigMigrator{
public static ConfigurationTransformation.Versioned create(){
return ConfigurationTransformation.versionedBuilder()
.versionKey("configVersion")
.addVersion(LATEST, fiveToSix())
.addVersion(LATEST, sixToSeven())
.addVersion(6, fiveToSix())
.addVersion(5, fourToFive())
.addVersion(4, threeToFour())
.addVersion(3, twoToThree())
@@ -54,6 +55,16 @@ public class ConfigMigrator{
.build();
}
public static ConfigurationTransformation sixToSeven(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path(), (path, value) -> {
value.node("printBanner").set(true);
return null;
})
.build();
}
public static ConfigurationTransformation fiveToSix(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path("disableDuringMaintenance"), (path, value) -> {
@@ -122,7 +133,7 @@ public class ConfigMigrator{
versioned.apply(node);
final int endVersion = versioned.version(node);
if(startVersion < endVersion)
logger.info("Migrated config.yml from v" + startVersion + " to v" + endVersion);
logger.success("Successfully migrated config from <white>v%d</white> to <white>v%d</white>", startVersion, endVersion);
}
return node;
@@ -72,7 +72,6 @@ public class FileHandler{
}
public boolean loadConfig(){
logger.info("Loading config.yml...");
File folder = plugin.getPlugin().getFolderPath().toFile();
if(!folder.exists() && !folder.mkdirs()){
logger.warn("Couldn't create folder for plugin. Is it missing Write permissions?");
@@ -87,7 +86,7 @@ public class FileHandler{
}
Files.copy(stream, config);
logger.info("Created new config.yml!");
logger.success("Created new config.yml!");
}catch(IOException ex){
logger.warn("Cannot create config.yml for plugin.", ex);
return false;
@@ -98,7 +97,7 @@ public class FileHandler{
}
public boolean loadProfiles(){
logger.info("Loading profiles...");
logger.info("[-] Loading profiles...");
if(createFile("default.yml")){
return reloadProfiles();
@@ -109,7 +108,7 @@ public class FileHandler{
public boolean createFile(String name){
if(Files.notExists(profilesFolder) && profilesFolder.toFile().mkdirs()){
logger.info("Successfully created profiles folder.");
logger.debugSuccess(FileHandler.class, "Successfully created profiles folder.");
}
File file = new File(profilesFolder.toFile(), name);
@@ -126,7 +125,7 @@ public class FileHandler{
Files.copy(stream, profilesFolder.resolve(name));
return true;
}catch(IOException ex){
logger.warn("Encountered IOException while trying to create file %s", ex, name);
logger.warn("Encountered IOException while trying to create file <white>%s</white>", ex, name);
return false;
}
}
@@ -160,7 +159,7 @@ public class FileHandler{
File[] files = profilesFolder.toFile().listFiles(((dir, name) -> name.endsWith(".yml")));
if(files == null || files.length == 0){
logger.warn("Cannot load files from profiles folder! No valid YAML files present.");
logger.failure("Cannot load files from profiles folder! No valid YAML files present.");
return false;
}
@@ -170,11 +169,11 @@ public class FileHandler{
continue;
profiles.add(ServerListProfile.Builder.resolve(file.getName(), tmp, logger).build());
logger.info("Loaded '%s'!", file.getName());
logger.debugSuccess(FileHandler.class, "Loaded '<white>%s</white>'!", file.getName());
}
if(profiles.isEmpty()){
logger.warn("Couldn't load any profile from profiles folder!");
logger.failure("Couldn't load any profile from profiles folder!");
return false;
}
@@ -191,7 +190,7 @@ public class FileHandler{
try{
return loader.load();
}catch(IOException ex){
logger.warn("Cannot load '%s' due to an IOException!", ex, path.toFile().getName());
logger.warn("Cannot load '<white>%s</white>' due to an IOException!", ex, path.toFile().getName());
return null;
}
}
@@ -218,11 +217,11 @@ public class FileHandler{
}
private boolean makeBackup(){
logger.info("Making backup of old config.yml...");
logger.info("[-] Making backup of old config.yml...");
File backups = plugin.getPlugin().getFolderPath().resolve("backups").toFile();
if(!backups.exists() && !backups.mkdirs()){
logger.warn("Cannot create backups folder for migration!");
logger.failure("Cannot create backups folder for migration!");
return false;
}
@@ -231,16 +230,16 @@ public class FileHandler{
File configBackup = new File(backups, "config_" + date.replace(":", "_") + ".yml");
try{
if(!configBackup.exists() && !configBackup.createNewFile()){
logger.warn("Cannot create backup file for config.yml!");
logger.failure("Cannot create backup file for config.yml!");
return false;
}
Files.copy(config, configBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
logger.info("Saved backup as '%s'!", configBackup.getName());
logger.success("Saved backup as '<white>%s</white>'!", configBackup.getName());
return true;
}catch(IOException ex){
logger.warn("Encountered IOException while trying to create a backup.", ex);
logger.failure("Encountered IOException while trying to create a backup.", ex);
return false;
}
}
@@ -27,10 +27,18 @@ package ch.andre601.advancedserverlist.core.interfaces;
public interface PluginLogger{
default void debugSuccess(Class<?> clazz, String msg, Object... args){
debug(clazz, "[<green>✓</green>] " + msg, args);
}
void debug(Class<?> clazz, String msg, Object... args);
void debugWarn(Class<?> clazz, String msg, Object... args);
default void success(String msg, Object... args){
info("[<green>✓</green>] " + msg, args);
}
void info(String msg, Object... args);
void warn(String msg, Object... args);
@@ -38,4 +46,8 @@ public interface PluginLogger{
void warn(String msg, Throwable throwable);
void warn(String msg, Throwable throwable, Object... args);
default void failure(String msg, Object... args){
warn("[<red>x</red>] " + msg, args);
}
}
@@ -52,6 +52,8 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
void setPlayers(List<String> players, P player, GenericServer server);
void setPlayersHidden();
void setFavicon(F favicon);
void setDefaultFavicon();
@@ -56,7 +56,7 @@ public class MiniMOTDConfigMigrator{
Path mainConf = core.getPlugin().getFolderPath().getParent().resolve(folder).resolve("main.conf");
if(!Files.exists(mainConf)){
logger.warn("[Migrator - MiniMOTD] Cannot find a main.conf file in /plugins/%s/ folder.", folder);
logger.warn("[<white>Migrator - MiniMOTD</white>] Cannot find a main.conf file in <white>/plugins/%s/</white> folder.", folder);
sender.sendErrorMsg(" -> <red>No main.conf file found.");
return false;
}
@@ -76,13 +76,13 @@ public class MiniMOTDConfigMigrator{
config = node.get(MiniMOTDConfig.class);
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered IOException while loading main.conf file.", ex);
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered IOException while loading main.conf file.", ex);
sender.sendErrorMsg(" -> <red>IOException while loading</red> main.conf <red>file.");
return false;
}
if(config == null){
logger.warn("[Migrator - MiniMOTD] Retrieved main.conf file returned null.");
logger.warn("[<white>Migrator - MiniMOTD</white>] Retrieved main.conf file returned null.");
sender.sendErrorMsg(" -> <red>Received invalid</red> main.conf <red>file.");
return false;
}
@@ -110,14 +110,14 @@ public class MiniMOTDConfigMigrator{
if(config.iconEnabled()){
if(config.motds().size() == 1){
MiniMOTDConfig.Motd motd = config.motds().get(0);
if(!motd.icon().isEmpty() && !motd.icon().equalsIgnoreCase("random")){
if(!motd.icon().isEmpty()){
profileBuilder.favicon(motd.icon());
}
}else
if(config.motds().size() > 1){
for(int i = 0; i < config.motds().size(); i++){
MiniMOTDConfig.Motd motd = config.motds().get(i);
if(!motd.icon().isEmpty() && !motd.icon().equalsIgnoreCase("random")){
if(!motd.icon().isEmpty()){
profilesBuilders.get(i).favicon(motd.icon());
}
}
@@ -147,14 +147,14 @@ public class MiniMOTDConfigMigrator{
boolean profilesInvalid = profiles.isEmpty() || profiles.stream().allMatch(ProfileEntry::isInvalid);
if(entry.isInvalid() && profilesInvalid){
logger.warn("[Migrator - MiniMOTD] Main ProfileEntry was invalid and profiles were empty.");
logger.warn("[<white>Migrator - MiniMOTD</white>] Main ProfileEntry was invalid and profiles were empty.");
sender.sendErrorMsg(" -> <red>Received invalid configuration.");
return false;
}
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve("minimotd_migrated.yml");
if(Files.exists(profile)){
logger.warn("[Migrator - MiniMOTD] Cannot create new file minimotd_migrated.yml. One with the same name is already present.");
logger.warn("[<white>Migrator - MiniMOTD</white>] Cannot create new file minimotd_migrated.yml. One with the same name is already present.");
sender.sendErrorMsg(" -> <red>File</red> minimotd_migrated.yml <red>already present.");
return false;
@@ -163,7 +163,7 @@ public class MiniMOTDConfigMigrator{
try{
Files.createFile(profile);
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered an IOException while trying to create file minimotd_migrated.yml.", ex);
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered an IOException while trying to create file minimotd_migrated.yml.", ex);
sender.sendErrorMsg(" -> <red>File creation error.");
return false;
@@ -180,14 +180,14 @@ public class MiniMOTDConfigMigrator{
try{
migrated = yamlLoader.load();
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered an IOException while trying to load file minimotd_migrated.yml.", ex);
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered an IOException while trying to load file minimotd_migrated.yml.", ex);
sender.sendErrorMsg(" -> <red>File loading error.");
return false;
}
if(migrated == null){
logger.warn("[Migrator - MiniMOTD] Cannot migrate Configuration. ConfigurationNode was null.");
logger.warn("[<white>Migrator - MiniMOTD</white>] Cannot migrate Configuration. ConfigurationNode was null.");
sender.sendErrorMsg(" -> <red>File loading error.");
return false;
@@ -202,7 +202,7 @@ public class MiniMOTDConfigMigrator{
migrated.set(entry);
}catch(SerializationException ex){
logger.warn("[Migrator - MiniMOTD] Encountered a SerializationException while setting values.", ex);
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered a SerializationException while setting values.", ex);
sender.sendErrorMsg(" -> <red>Error while updating file</red> minimotd_migrated.yml<red>.");
return false;
@@ -214,7 +214,7 @@ public class MiniMOTDConfigMigrator{
return true;
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered an IOException while trying to save new file minimotd_migrated.yml.", ex);
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered an IOException while trying to save new file minimotd_migrated.yml.", ex);
sender.sendErrorMsg(" -> <red>File saving error.");
return false;
@@ -59,26 +59,55 @@ public class SLPConfigMigrator{
"(?<end>#[a-fA-F0-9]{6})" + // Ending color
"%" +
"(?<text>.+?)" + // Text
"%gradient%");
"%gradient%"
);
private static final Map<String, String> STATIC_REPLACEMENTS = Map.of(
"%player%", "${player name}",
"%uuid%", "${player uuid}",
"%_uuid_%", "${player uuid}",
"%online%", "${server playersOnline}",
"%max%", "${server playersMax}");
"%max%", "${server playersMax}"
);
private static final Map<String, String> COLOR_TO_MINIMESSAGE_TAG = new HashMap<>(){{
// Color Codes.
put("a", "<green>");
put("b", "<aqua>");
put("c", "<red>");
put("d", "<light_purple>");
put("e", "<yellow>");
put("f", "<white>");
put("0", "<black>");
put("1", "<dark_blue>");
put("2", "<dark_green>");
put("3", "<dark_aqua>");
put("4", "<dark_red>");
put("5", "<dark_purple>");
put("6", "<gold>");
put("7", "<grey>");
put("8", "<dark_grey>");
put("9", "<blue>");
// Formatting Codes
put("k", "<obfuscated>");
put("l", "<bold>");
put("m", "<strikethrough>");
put("n", "<underlined>");
put("o", "<italic>");
put("r", "<reset>");
}};
public static int migrate(AdvancedServerList<?> core, CmdSender sender){
ServerListPlusCore slpCore = ServerListPlusCore.getInstance();
PluginLogger logger = core.getPlugin().getPluginLogger();
if(slpCore == null){
logger.warn("[Migrator - ServerListPlus] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
return 0;
}
ServerStatusConf conf = slpCore.getConf(ServerStatusConf.class);
if(conf == null){
logger.warn("[Migrator - ServerListPlus] Cannot migrate ServerListPlus configuration. Received configuration was null.");
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus configuration. Received configuration was null.");
return 0;
}
@@ -101,7 +130,7 @@ public class SLPConfigMigrator{
private static int parseConf(AdvancedServerList<?> core, CmdSender sender, PersonalizedStatusConf.StatusConf conf, Type type){
PluginLogger logger = core.getPlugin().getPluginLogger();
if(conf == null){
logger.info("[Migrator - ServerListPlus] No StatusConf found for type %s. Skipping...", type.getName());
logger.info("[<white>Migrator - ServerListPlus</white>] No StatusConf found for type <white>%s</white>. Skipping...", type.getName());
sender.sendPrefixedMsg(" -> Not found! Skipping...");
return 0;
@@ -141,7 +170,7 @@ public class SLPConfigMigrator{
boolean profilesInvalid = profileEntries.isEmpty() || profileEntries.stream().anyMatch(ProfileEntry::isInvalid);
if(entry.isInvalid() && profilesInvalid){
logger.warn("[Migrator - ServerListPlus] Unable to parse ServerListPlus configuration of type %s. Generated ProfileEntry was invalid.", type.getName());
logger.warn("[<white>Migrator - ServerListPlus</white>] Unable to parse ServerListPlus configuration of type <white>%s</white>. Generated ProfileEntry was invalid.", type.getName());
sender.sendErrorMsg(" -> <red>Received invalid Configuration.");
return 0;
@@ -149,7 +178,7 @@ public class SLPConfigMigrator{
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve(type.getFile());
if(Files.exists(profile)){
logger.warn("[Migrator - ServerListPlus] Cannot create new file %s. One with the same name is already present", type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot create new file <white>%s</white>. One with the same name is already present", type.getFile());
sender.sendErrorMsg(" -> <red>File</red> %s <red>already present.", type.getFile());
return 0;
@@ -158,7 +187,7 @@ public class SLPConfigMigrator{
try{
Files.createFile(profile);
}catch(IOException ex){
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to create file %s.", ex, type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to create file <white>%s</white>.", ex, type.getFile());
sender.sendErrorMsg(" -> <red>File creation error.");
return 0;
@@ -175,14 +204,14 @@ public class SLPConfigMigrator{
try{
node = loader.load();
}catch(IOException ex){
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to load file %s.", ex, type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to load file <white>%s</white>.", ex, type.getFile());
sender.sendErrorMsg(" -> <red>File loading error.");
return 0;
}
if(node == null){
logger.warn("[Migrator - ServerListPlus] Cannot migrate Configuration of type %s. ConfigurationNode was null.", type.getName());
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate Configuration of type <white>%s</white>. ConfigurationNode was null.", type.getName());
sender.sendErrorMsg(" -> <red>File loading error.");
return 0;
@@ -194,9 +223,7 @@ public class SLPConfigMigrator{
if(type == Type.PERSONALIZED){
node.node("condition")
.set("${player name} != \"" +
core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") +
"\"");
.set("${player name} != \"" + core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") + "\"");
}else
if(type == Type.BANNED){
node.node("condition")
@@ -209,7 +236,7 @@ public class SLPConfigMigrator{
node.set(entry);
}catch(SerializationException ex){
logger.warn("[Migrator - ServerListPlus] Encountered a SerializationException while setting values.", ex);
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered a SerializationException while setting values.", ex);
sender.sendErrorMsg(" -> <red>Error while updating file</red> %s<red>.", type.getFile());
return 0;
@@ -221,7 +248,7 @@ public class SLPConfigMigrator{
return 1;
}catch(IOException ex){
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to save new file %s.", ex, type.getFile());
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to save new file <white>%s</white>.", ex, type.getFile());
sender.sendErrorMsg(" -> <red>File saving error.");
return 0;
@@ -372,32 +399,11 @@ public class SLPConfigMigrator{
if(colorCodeMatcher.find()){
builder.setLength(0);
do{
String color = colorCodeMatcher.group("color").toLowerCase(Locale.ROOT);
switch(color){
case "a" -> colorCodeMatcher.appendReplacement(builder, "<green>");
case "b" -> colorCodeMatcher.appendReplacement(builder, "<aqua>");
case "c" -> colorCodeMatcher.appendReplacement(builder, "<red>");
case "d" -> colorCodeMatcher.appendReplacement(builder, "<light_purple>");
case "e" -> colorCodeMatcher.appendReplacement(builder, "<yellow>");
case "f" -> colorCodeMatcher.appendReplacement(builder, "<white>");
case "k" -> colorCodeMatcher.appendReplacement(builder, "<obfuscated>");
case "l" -> colorCodeMatcher.appendReplacement(builder, "<bold>");
case "m" -> colorCodeMatcher.appendReplacement(builder, "<strikethrough>");
case "n" -> colorCodeMatcher.appendReplacement(builder, "<underlined>");
case "o" -> colorCodeMatcher.appendReplacement(builder, "<italic>");
case "r" -> colorCodeMatcher.appendReplacement(builder, "<reset>");
case "0" -> colorCodeMatcher.appendReplacement(builder, "<black>");
case "1" -> colorCodeMatcher.appendReplacement(builder, "<dark_blue>");
case "2" -> colorCodeMatcher.appendReplacement(builder, "<dark_green>");
case "3" -> colorCodeMatcher.appendReplacement(builder, "<dark_aqua>");
case "4" -> colorCodeMatcher.appendReplacement(builder, "<dark_red>");
case "5" -> colorCodeMatcher.appendReplacement(builder, "<dark_purple>");
case "6" -> colorCodeMatcher.appendReplacement(builder, "<gold>");
case "7" -> colorCodeMatcher.appendReplacement(builder, "<grey>");
case "8" -> colorCodeMatcher.appendReplacement(builder, "<dark_grey>");
case "9" -> colorCodeMatcher.appendReplacement(builder, "<blue>");
// This one shouldn't be reachable given the pattern, but you never know...
default -> colorCodeMatcher.appendReplacement(builder, "&" + color);
for(Map.Entry<String, String> colorCodes : COLOR_TO_MINIMESSAGE_TAG.entrySet()){
if(!colorCodeMatcher.group("color").equalsIgnoreCase(colorCodes.getKey()))
continue;
colorCodeMatcher.appendReplacement(builder, colorCodes.getValue());
}
}while(colorCodeMatcher.find());
@@ -29,7 +29,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.List;
import java.util.function.Function;
public class ComponentParser{
@@ -52,12 +51,13 @@ public class ComponentParser{
return new ComponentParser(text);
}
public static ComponentParser list(List<String> lines){
return new ComponentParser(String.join("\n", lines));
public static ComponentParser textFormatted(String text, Object... args){
return text(String.format(text, args));
}
public ComponentParser modifyText(Function<String, String> function){
this.text = function.apply(text);
return this;
}
@@ -73,4 +73,8 @@ public class ComponentParser{
public String toString(){
return legacy.serialize(toComponent());
}
public String toStringStriped(){
return mm.stripTags(text);
}
}
@@ -0,0 +1,136 @@
package ch.andre601.advancedserverlist.core.parsing;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.kyori.adventure.text.flattener.ComponentFlattener;
import net.kyori.adventure.text.flattener.FlattenerListener;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class TextCenterUtil{
private final ComponentFlattener COMPONENT_FLATTENER = ComponentFlattener.textOnly();
private final double MAX_WIDTH = 270.0; // Max width of the MOTD
private final int SPACE_WIDTH = 4;
private final Map<String, FontInfo> charWidths;
public TextCenterUtil(AdvancedServerList<?> plugin){
charWidths = loadFontWidths(plugin);
}
public String getCenteredText(String text){
if(!text.toLowerCase(Locale.ROOT).startsWith("<center>"))
return text;
if(getDefault() == null)
return text;
text = text.substring("<center>".length());
TextFlattenerListener listener = new TextFlattenerListener(this);
COMPONENT_FLATTENER.flatten(ComponentParser.text(text).toComponent(), listener);
double width = listener.getWidth();
if(width >= MAX_WIDTH)
return text;
return createSpaces(width) + text;
}
private double getCharWidth(int codePoint, boolean isBold, String fontName){
FontInfo font = charWidths.getOrDefault(fontName, getDefault());
if(font == null)
return -1.0;
int index = Arrays.binarySearch(font.codePoints, codePoint);
if(index < 0){
return isBold ? 7.0 : 6.0;
}else{
return isBold ? font.advanceBf[index] : font.advance[index];
}
}
private FontInfo getDefault(){
return charWidths.get("minecraft:default");
}
private String createSpaces(double length){
double remainder = MAX_WIDTH - length;
int padding = (int)Math.max(0, Math.floor(remainder / 2.0) - 1);
return " ".repeat(Math.floorDiv(padding, SPACE_WIDTH));
}
private Map<String, FontInfo> loadFontWidths(AdvancedServerList<?> plugin){
try(InputStream stream = plugin.getClass().getResourceAsStream("/char-widths.json.gz")){
if(stream == null){
plugin.getPlugin().getPluginLogger().warn("Internal char-widths.json.gz couldn't be retrieved.");
plugin.getPlugin().getPluginLogger().warn("The <center> Placeholder won't work.");
return new HashMap<>();
}
GZIPInputStream gzipStream = new GZIPInputStream(stream);
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipStream));
return new Gson().fromJson(reader, new TypeToken<Map<String, FontInfo>>(){}.getType());
}catch(IOException ex){
plugin.getPlugin().getPluginLogger().warn("Encountered IOException while loading font widths.");
plugin.getPlugin().getPluginLogger().warn("The <center> Placeholder won't work.");
plugin.getPlugin().getPluginLogger().warn("Cause: <white>%s</white>", ex.getMessage());
return new HashMap<>();
}
}
private static class TextFlattenerListener implements FlattenerListener{
private double width = 0.0;
private boolean isBold = false;
private String font = "minecraft:default";
private final TextCenterUtil instance;
public TextFlattenerListener(TextCenterUtil instance){
this.instance = instance;
}
@Override
public void pushStyle(@NotNull Style style){
if(style.hasDecoration(TextDecoration.BOLD))
isBold = true;
if(style.font() != null)
font = style.font().asString();
}
@Override
public void component(@NotNull String text){
for(int i = 0; i < text.length(); i++){
width += instance.getCharWidth(text.codePointAt(i), isBold, font);
}
}
@Override
public void popStyle(@NotNull Style style){
if(style.hasDecoration(TextDecoration.BOLD))
isBold = false;
}
public double getWidth(){
return width;
}
}
private record FontInfo(int[] codePoints, float[] advance, float[] advanceBf){}
}
@@ -51,13 +51,13 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
boolean result = core.getParser().evaluate(condition, player, server, collector);
if(collector.hasWarnings()){
logger.warn("Encountered %d Error(s) while parsing condition for file '%s':", collector.getWarnings().size(), file);
logger.warn("Encountered <white>%d</white> Error(s) while parsing condition for file '<white>%s</white>':", collector.getWarnings().size(), file);
for(ParseWarnCollector.Context context : collector.getWarnings()){
logger.warn(" - At position %s:", context.position() == -1 ? "Unknown" : context.position());
logger.warn(" %s", condition);
logger.warn(" ".repeat(context.position() + 4) + "^");
logger.warn(" -> %s", context.message());
logger.warn(" - At position <white>%s</white>:", context.position() == -1 ? "<italic>Unknown</italic>" : context.position());
logger.warn(" <white>%s</white>", condition);
logger.warn(" ".repeat(context.position() + 3) + "<red>^</red>");
logger.warn(" <grey>-></grey> %s", context.message());
}
}
@@ -146,7 +146,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
try{
this.profiles = node.node("profiles").getList(ProfileEntry.class);
}catch(SerializationException ex){
logger.warn("Encountered a SerializationException while resolving the profiles entry for %s", ex, fileName);
logger.warn("Encountered a SerializationException while resolving the profiles entry for <white>%s</white>", ex, fileName);
}
return this;
@@ -159,7 +159,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
try{
this.defaultProfile = node.get(ProfileEntry.class);
}catch(SerializationException ex){
logger.warn("Encountered a SerializationException while resolving the global profile for %s", ex, fileName);
logger.warn("Encountered a SerializationException while resolving the global profile for <white>%s</white>", ex, fileName);
}
return this;
}
@@ -76,7 +76,14 @@ public class CustomExpressionTokenizer{
}
}
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
if(position.getIndex() >= text.length()){
collector.appendWarningFormatted(
"Current index position (%d) is larger or equal to Text length (%d) for condition '%s'",
position.getIndex(), text.length(), text
);
}else{
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
}
break;
}
@@ -91,7 +91,7 @@ public class FaviconHandler<F>{
logger.debug(FaviconHandler.class, "Getting Favicon image from cache...");
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
}catch(ExecutionException ex){
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
logger.warn("Received ExecutionException while retrieving Favicon for '<white>%s</white>'.", ex, input);
return null;
}
}
@@ -137,15 +137,15 @@ public class FaviconHandler<F>{
private void loadLocalFavicons(){
this.localFavicons.clear();
logger.info("Loading local image files as Favicons...");
logger.info("[-] Loading local image files as Favicons...");
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
if(!Files.exists(folder)){
try{
Files.createDirectories(folder);
logger.info("Created favicons folder.");
logger.debugSuccess(FaviconHandler.class, "Created favicons folder.");
}catch(IOException ex){
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
logger.failure("Cannot create favicons folder. Encountered an IOException.", ex);
return;
}
}
@@ -154,8 +154,10 @@ public class FaviconHandler<F>{
pathStream.filter(Files::isRegularFile)
.filter(file -> file.getFileName().toString().endsWith(".png"))
.forEach(this::loadFile);
logger.success("Loaded <white>%d</white> local Favicons.", localFavicons.size());
}catch(IOException ex){
logger.warn("Cannot load files from Favicons folder.", ex);
logger.failure("Cannot load files from favicons folder.", ex);
}
}
@@ -163,14 +165,14 @@ public class FaviconHandler<F>{
try(InputStream stream = Files.newInputStream(path)){
F favicon = createFavicon(stream);
if(favicon == null){
logger.warn("Cannot create Favicon from file '%s'. Received Favicon was null.", path.getFileName().toString());
logger.failure("Cannot create Favicon from file '<white>%s</white>'. Received Favicon was null.", path.getFileName().toString());
return;
}
localFavicons.put(path.getFileName().toString().toLowerCase(Locale.ROOT), favicon);
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
logger.debugSuccess(FaviconHandler.class, "Loaded file '<white>%s</white>' as Favicon.", path.getFileName().toString());
}catch(IOException ex){
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
logger.failure("Cannot create Favicon from file '<white>%s</white>'. Encountered IOException.", ex);
}
}
@@ -185,11 +187,11 @@ public class FaviconHandler<F>{
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
return createFavicon(stream);
}catch(InterruptedException | IOException ex){
logger.warn("Cannot create Favicon from URL '%s'. Encountered an Exception.", ex, url);
logger.warn("Cannot create Favicon from URL '<white>%s</white>'. Encountered an Exception.", ex, url);
return null;
}
}catch(URISyntaxException ex){
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
logger.warn("Cannot create Favicon from URL '<white>%s</white>'. Encountered a URISyntaxException.", ex, url);
return null;
}
}
@@ -79,40 +79,40 @@ public class PlayerHandler{
try(BufferedReader reader = Files.newBufferedReader(cache)){
cachedPlayers = gson.fromJson(reader, listType);
}catch(IOException ex){
logger.warn("Encountered IOException while reading the playercache.json file!", ex);
logger.warn("Encountered IOException while reading the <white>playercache.json</white> file!", ex);
return;
}catch(JsonIOException | JsonSyntaxException ex){
logger.warn("Encountered JsonSyntaxException while parsing playercache.json file!", ex);
logger.warn("Encountered JsonSyntaxException while parsing <white>playercache.json</white> file!", ex);
return;
}
// In case Gson messes up... I guess.
if(cachedPlayers == null){
logger.warn("Couldn't load players from playercache.json file. Is the JSON valid?");
logger.warn("Couldn't load players from <white>playercache.json</white> file. Is the JSON valid?");
// Create new ArrayList instance to avoid further issues.
cachedPlayers = new ArrayList<>();
return;
}
logger.info("Loaded %d players into cache!", cachedPlayers.size());
logger.success("Loaded <white>%d</white> players into cache!", cachedPlayers.size());
}
public void save(){
if(cachedPlayers.isEmpty()){
logger.info("No players in cache to save. Skipping...");
logger.debug(PlayerHandler.class, "No players in cache to save. Skipping...");
return;
}
if(core.getFileHandler().getBoolean("disableCache")){
logger.info("'disable_cache' is set to true. Skipping saving of cached players...");
logger.debug(PlayerHandler.class, "[-] 'disable_cache' is set to true. Not saving cached players.");
return;
}
try(BufferedWriter writer = Files.newBufferedWriter(cache, StandardCharsets.UTF_8)){
gson.toJson(cachedPlayers, listType, writer);
logger.info("Successfully saved playercache.json file.");
logger.success("Successfully saved <white>playercache.json</white> file.");
}catch(IOException ex){
logger.warn("Encountered IOException while saving cached players to playercache.json!", ex);
logger.failure("Encountered IOException while saving cached players to <white>playercache.json</white>!", ex);
}
}
@@ -56,6 +56,7 @@ public class ProfileManager{
NullBool extraPlayersEnabled = resolve(defEntry, entry, ProfileEntry::extraPlayersEnabled);
NullBool maxPlayersEnabled = resolve(defEntry, entry, ProfileEntry::maxPlayersEnabled);
NullBool onlinePlayersEnabled = resolve(defEntry, entry, ProfileEntry::onlinePlayersEnabled);
NullBool hidePlayersHoverEnabled = resolve(defEntry, entry, ProfileEntry::hidePlayersHoverEnabled);
String extraPlayersCount = resolve(defEntry, entry, ProfileEntry::extraPlayersCount);
String maxPlayersCount = resolve(defEntry, entry, ProfileEntry::maxPlayersCount);
String onlinePlayersCount = resolve(defEntry, entry, ProfileEntry::onlinePlayersCount);
@@ -69,6 +70,7 @@ public class ProfileManager{
.extraPlayersEnabled(extraPlayersEnabled)
.maxPlayersEnabled(maxPlayersEnabled)
.onlinePlayersEnabled(onlinePlayersEnabled)
.hidePlayersHoverEnabled(hidePlayersHoverEnabled)
.extraPlayersCount(extraPlayersCount)
.maxPlayersCount(maxPlayersCount)
.onlinePlayersCount(onlinePlayersCount)
@@ -96,6 +98,7 @@ public class ProfileManager{
NullBool extraPlayersEnabled = resolveNullBool(node, "playerCount", "extraPlayers", "enabled");
NullBool maxPlayersEnabled = resolveNullBool(node, "playerCount", "maxPlayers", "enabled");
NullBool onlinePlayersEnabled = resolveNullBool(node, "playerCount", "onlinePlayers", "enabled");
NullBool hidePlayersHoverEnabled = resolveNullBool(node, "playerCount", "hidePlayersHover");
String extraPlayers = resolveNullableString(node, "playerCount", "extraPlayers", "amount");
String maxPlayers = resolveNullableString(node, "playerCount", "maxPlayers", "amount");
String onlinePlayers = resolveNullableString(node, "playerCount", "onlinePlayers", "amount");
@@ -109,6 +112,7 @@ public class ProfileManager{
.extraPlayersEnabled(extraPlayersEnabled)
.maxPlayersEnabled(maxPlayersEnabled)
.onlinePlayersEnabled(onlinePlayersEnabled)
.hidePlayersHoverEnabled(hidePlayersHoverEnabled)
.extraPlayersCount(extraPlayers)
.maxPlayersCount(maxPlayers)
.onlinePlayersCount(onlinePlayers)
@@ -53,6 +53,7 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
node.node("playerCount", "text").set(profile.playerCountText());
node.node("favicon").set(profile.favicon());
node.node("playerCount", "hidePlayers").set(profile.hidePlayersEnabled().getOrDefault(false));
node.node("playerCount", "hidePlayersHover").set(profile.hidePlayersHoverEnabled().getOrDefault(false));
node.node("playerCount", "extraPlayers", "enabled").set(profile.extraPlayersEnabled().getOrDefault(false));
node.node("playerCount", "extraPlayers", "amount").set((profile.extraPlayersCount() == null) ? "0" : profile.extraPlayersCount());
node.node("playerCount", "maxPlayers", "enabled").set(profile.maxPlayersEnabled().getOrDefault(false));
@@ -72,6 +72,9 @@ public class StringReplacer{
boolean identified = false;
boolean invalid = true;
int placeholderStart = position.getIndex() - 1;
int valueStart = position.getIndex() - 1;
char[] chars = input.substring(index).toCharArray();
for(final char c : chars){
index++;
@@ -83,6 +86,7 @@ public class StringReplacer{
if(c == ' ' && !identified){
identified = true;
valueStart = index + 1;
continue;
}
@@ -98,10 +102,6 @@ public class StringReplacer{
StringBuilder raw = new StringBuilder();
// Condition parsing needs one extra increase of index... for some reason
if(collector != null)
index++;
position.setIndex(index);
if(invalid){
@@ -111,7 +111,7 @@ public class StringReplacer{
raw.append(' ').append(valuesStr);
if(collector != null)
collector.appendWarningFormatted(index, "Placeholder '%s' does not have a closing bracket (})", raw.toString());
collector.appendWarningFormatted(index, "Placeholder '<white>%s</white>' does not have a closing bracket (})", raw.toString());
return raw.toString();
}
@@ -126,7 +126,7 @@ public class StringReplacer{
raw.append('}');
if(collector != null)
collector.appendWarningFormatted(index, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
collector.appendWarningFormatted(placeholderStart, "Placeholder '<white>%s</white>' does not have any available PlaceholderProvider", raw.toString());
return raw.toString();
}
@@ -141,7 +141,7 @@ public class StringReplacer{
raw.append('}');
if(collector != null)
collector.appendWarningFormatted(index, "Placeholder '%s' has an invalid value String '%s'", raw.toString(), valuesStr);
collector.appendWarningFormatted(valueStart, "Placeholder '<white>%s</white>' has an invalid value String '<white>%s</white>'", raw.toString(), valuesStr);
return raw.toString();
}
Binary file not shown.
+8
View File
@@ -48,6 +48,14 @@ checkUpdates: true
#
debug: false
#
# Should the "ASL" ASCI art be displayed on plugin startup?
# Setting this to false will hide the banner.
#
# Default: true
#
printBanner: true
#
# Sets how long Favicons should be cached. Value is in minutes with the lowest possible value being 1.
#
+9 -4
View File
@@ -58,12 +58,17 @@ motd:
# This option supports three types of inputs:
#
# 1. Name, including .png extension, pointing to an image located in the plugin's favicons folder.
# 2. URL pointing to an image.*
# 3. Player name, UUID or placeholders returning one of these.*
# 2. "random" to display a random PNG from the favicons folder.
# 3. URL pointing to an image.
# 4. Player name, UUID or placeholders returning one of these.
# https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
#
# * These images are loaded asynchronously, meaning they may not yet be "ready" when AdvancedServerList is done with
# the event, requiring a refresh of the server list by the player to have it shown.
# Note on favicons not showing:
# AdvancedServerList has to create a Favicon object for the Proxy/Server to use which takes time to do so.
# To not delay the Proxy/Server from being displayed (increase the loading time on the player end) is this creation
# done asynchronously for URL/Player name/UUID. This has the downside that the Proxy/Server may be done handling the
# ping before the Favicon is created, causing none to be displayed.
# Note that this won't happen with local favicons, as those are created during the plugin's startup.
#
# Any images above or below 64x64 pixels will be automatically resized to these dimensions.
#
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.test;
package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.test;
package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.expressionparser.ParseWarnCollector;
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.test;
package ch.andre601.advancedserverlist.core;
import com.unascribed.flexver.FlexVerComparator;
import org.junit.jupiter.api.Test;
+1 -1
View File
@@ -17,7 +17,7 @@
import re
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import File, Files
from mkdocs.structure.files import Files
from mkdocs.structure.pages import Page
def on_page_markdown(
+7
View File
@@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block announce %}
<span class="twemoji">{% include ".icons/material/party-popper.svg" %}</span>
Celebrating <a href="https://andre601.ch/blog/2024/12-13-history-of-asl/" target="_blank" rel="nofollow"><b>25,000 downloads!</b></a> Thank you!
<span class="twemoji">{% include ".icons/material/party-popper.svg" %}</span>
{% endblock %}
+10
View File
@@ -0,0 +1,10 @@
[discord]: https://discord.gg/MyPTjpsgGH
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
[modrinth]: https://modrinth.com/plugin/advancedserverlist
[hangar]: https://hangar.papermc.io/Andre_601/AdvancedServerList
[codeberg]: https://codeberg.org/Andre601/AdvancedServerList
+4 -1
View File
@@ -1,9 +1,12 @@
---
icon: octicons/stop-24
---
# BanPlugins Addon
The BanPlugins Addon was made to provide placeholders for different punishment plugins to use in AdvancedServerList.
/// info
The BanPlugins Addon is available in downloads of AdvancedServerList on [:simple-modrinth: Modrinth](https://modrinth.com/plugin/advancedserverlist) and on [Releases on :simple-codeberg: Codeberg](https://codeberg.org/Andre601/AdvancedServerList/releases).
The BanPlugins Addon is available in downloads of AdvancedServerList on [:simple-modrinth: Modrinth](https://modrinth.com/plugin/advancedserverlist) and in [Releases on :simple-codeberg: Codeberg](https://codeberg.org/Andre601/AdvancedServerList/releases).
///
## Placeholders
+16 -10
View File
@@ -7,6 +7,15 @@ icon: octicons/log-24
This page lists the recent changes made towards the AdvancedServerListAPI.
They are ordered newest to oldest.
## v4.1.0 { #v4.1.0 }
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v-added }
- New setter method added to [`ProfileEntry.Builder`][profileentry.builder] class:
- [`hidePlayersHoverEnabled(NullBool)`][hidePlayersHoverEnabled]
[hidePlayersHoverEnabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#hideplayershoverenabled(nullbool)
## v4.0.0 { #v4.0.0 }
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v4.0.0-breaking }
@@ -17,11 +26,11 @@ They are ordered newest to oldest.
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v4.0.0-added }
- New setter methods added to [`ProfileEntry.Builder`][profilentry.builder] class:
- New setter methods added to [`ProfileEntry.Builder`][profileentry.builder] class:
- [`onlinePlayersCount(String)`][onlinePlayersCount]
- [`onlinePlayersEnabled(NullBool)`][onlinePlayersEnabled]
[onlinePlayersCount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayerscount(integer)
[onlinePlayersCount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayerscount(string)
[onlinePlayersEnabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayersenabled(nullbool)
## v3.3.0 { #v3.3.0 }
@@ -53,11 +62,11 @@ They are ordered newest to oldest.
- [`playerCountText(String)`][playercounttext]
- [`players(List<String>)`][players]
[extraplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayerscount(integer)
[extraplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayerscount(string)
[extraplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayersenabled(nullbool)
[favicon]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#favicon(string)
[hideplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#hideplayersenabled(nullbool)
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayerscount(integer)
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayerscount(string)
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayersenabled(nullbool)
[motd]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#motd(list<string>)
[playercounttext]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#playercounttext(string)
@@ -119,9 +128,9 @@ They are ordered newest to oldest.
- [`maxPlayersEnabled()`][maxplayersenabled] - Returns the value for `playerCount -> maxPlayers -> enabled` as `NullBool`
- [`maxPlayersCount()`][maxplayerscount] - Returns the value of `playerCount -> maxPlayers -> amount` as nullable `Integer`
- New setters in [`ProfileEntry.Builder`][profileentry.builder]:
- [`setMaxPlayersEnabled(NullBool)`][setmaxplayersenabled] - Sets whether the max players feature is enabled or not.
- [`setMaxPlayersCount(Integer)`][setmaxplayerscount] - Sets the number to use for the max players count.
- [`setExtraPlayersCount(Integer)`][setextraplayersecount] - Replacement for [deprecated `setExtraPlayerCount(Integer)` method](#v3.1.0-deprecated).
- `setMaxPlayersEnabled(NullBool)`- Sets whether the max players feature is enabled or not.
- `setMaxPlayersCount(Integer)` - Sets the number to use for the max players count.
- `setExtraPlayersCount(Integer)` - Replacement for [deprecated `setExtraPlayerCount(Integer)` method](#v3.1.0-deprecated).
### :octicons-zap-24:{ .changelog-breaking title="Deprecated" } Deprecated { #v3.1.0-deprecated }
@@ -132,9 +141,6 @@ They are ordered newest to oldest.
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayerscount()
[profileentry.builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
[setmaxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setmaxplayersenabled(nullbool)
[setmaxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setmaxplayerscount(integer)
[setextraplayersecount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setextraplayerscount(integer)
----
+12 -14
View File
@@ -11,7 +11,7 @@ AdvancedServerList offers an API that other plugins can use to add their own pla
Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depending on what you use:
/// tab | :simple-apachemaven: Maven
```xml title="pom.xml"
```xml { data-md-component="api-version" title="pom.xml" }
<repositories>
<repository>
<id>codeberg</id>
@@ -51,7 +51,7 @@ Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depend
///
/// tab | :simple-gradle: Gradle
```groovy title="build.gradle"
```groovy { data-md-component="api-version" title="build.gradle" }
repositorories {
maven { url = 'https://codeberg.org/api/packages/Andre601/maven/' }
}
@@ -68,7 +68,7 @@ dependencies {
///
/// tab | :simple-gradle: Gradle (KTS)
```kotlin title="build.gradle.kts"
```kotlin { data-md-component="api-version" title="build.gradle.kts" }
repositories {
maven("https://codeberg.org/api/packages/Andre601/maven/")
}
@@ -96,11 +96,11 @@ To add your own placeholders, follow these steps:
You should first create a new class and make it extend the abstract [`PlaceholderProvider`][placeholderprovider]. This class includes a constructor and a method you need to add, so do that:
```java
```java { .annotate title="Creating PlaceholderProvider class" }
public class MyPlaceholders extends PlaceholderProvider {
public MyPlaceholders(String identifier) {
super(identifier);
super(identifier); // (1)
}
@Override
@@ -110,14 +110,12 @@ public class MyPlaceholders extends PlaceholderProvider {
}
```
/// tip
You can replace the Constructor with a String argument with a no-args constructor and set the identifier directly in the `super`:
```java
public MyPlaceholders() {
super("myplaceholders");
}
```
///
1. It is recommended to replace this constructor with a no-args Constructor and have the placeholder name set in the `super` directly:
```java
public MyPlaceholders() {
super("myplaceholders");
}
```
The [`parsePlaceholder(String, GenericPlayer, GenericServer)`][parseplaceholder] method is used by AdvancedServerList to replace a matching placeholder with a value.
What you return is completely up to you. Just keep in mind that returning `null` will be treated as an invalid placeholder by AdvancedServerList, resulting in the placeholder being returned as-is without any changes.
@@ -128,7 +126,7 @@ What you return is completely up to you. Just keep in mind that returning `null`
/// details | Example of final class
type: example
```java
```java title="MyPlaceholders.java"
public class MyPlaceholders extends PlaceholderProvider {
public MyPlaceholders() {
@@ -13,14 +13,16 @@ constructors:
methods:
- name: 'extraPlayersCount'
description: |
Sets the number of players to add to the online players to use as the new max players value.<br>
Sets the value to resolve into a number by AdvancedServerList.<br>
Strings not resolving into valid numbers will be treated as this option not being set.<br>
<br>
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
<br>
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
Set this to <code>null</code> to not alter the max player count. Alternatively <a href="#setextraplayersenabled(nullbool)"><code>disable extra Players</code></a>.
parameters:
- name: 'extraPlayersCount'
description: 'The number of extra players to add.'
type: 'Integer'
type: 'String'
attribute:
- 'nullable'
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
@@ -71,9 +73,26 @@ methods:
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
- name: 'hidePlayersHoverEnabled'
description: |
Sets ehther the Hover List of online Players should be hidden or not.<br>
<br>
Set to <a href="../../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
parameters:
- name: 'hidePlayersHoverEnabled'
description: 'Whether the online players feature should be enabled or not.'
type: 'NullBool'
attribute:
- 'notnull'
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
- name: 'maxPlayersCount'
description: |
Sets the number of max players allowed to join this server.<br>
Sets the value to resolve into a number by AdvancedServerList.<br>
Strings not resolving into valid numbers will be treated as this option not being set.<br>
<br>
This option has no effect when <a href="#maxplayersenabled(nullbool)">maxPlayersEnabled</a> is set to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
<br>
Set this to <code>null</code> to not alter the max player count. Alternatively <a href="#maxplayersenabled(nullbool)">disable max Players</a>.
@@ -122,7 +141,11 @@ methods:
- name: 'onlinePlayersCount'
description: |
Sets the value to resolve into a number by AdvancedServerList.<br>
Strings not resolving into valid numbers will be treated as this option not being set.
Strings not resolving into valid numbers will be treated as this option not being set.<br>
<br>
This option has no effect when <a href="#onlineplayersenabled(nullbool)">maxPlayersEnabled</a> is set to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
<br>
Set this to <code>null</code> to not alter the online player count. Alternatively <a href="#onlineplayersenabled(nullbool)">disable online Players</a>.
parameters:
- name: 'onlinePlayersCount'
description: 'The number of online players to set.'
@@ -42,14 +42,24 @@ constructors:
type: NullBool
attributes:
- notnull
- name: 'onlinePlayersCount'
description: 'The number to set for the Online Players count.'
type: String
attributes:
- nullable
- name: 'hidePlayersHoverEnabled'
description: 'Whether the online Players Hover should beenabled.'
type: NullBool
attributes:
- notnull
- name: 'extraPlayersCount'
description: 'The number to add to the online players for the max players number.'
type: Integer
description: 'The number to add to the online Players for the extra Players.'
type: String
attributes:
- nullable
- name: 'maxPlayersCount'
description: 'The number to use for the max players count.'
type: Integer
description: 'The number to set for the max Players count.'
type: String
attributes:
- nullable
seealso:
@@ -74,8 +84,11 @@ methods:
<li><a href="#hideplayersenabled()"><code>hidePlayersEnabled</code></a>: <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a></li>
<li><a href="#extraplayersenabled()"><code>extraPlayersEnabled</code></a>: <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a></li>
<li><a href="#maxplayersenabled()"><code>maxPlayersEnabled</code></a>: <a href="../../objects/nullbool/#not_set"><code>NullBoo.NOT_SET</code></a></li>
<li><a href="#onlineplayersenabled()"><code>onlinePlayersEnabled</code></a>: <a href="../../objects/nullbool/#not_set"><code>NullBoo.NOT_SET</code></a></li>
<li><a href="#hideplayershoverenabled()"><code>hidePlayersHoverEnabled</code></a>: <a href="../../objects/nullbool/#not_set"><code>NullBoo.NOT_SET</code></a></li>
<li><a href="#extraplayerscount()"><code>extraPlayersCount</code></a>: <code>null</code></li>
<li><a href="#maxplayerscount()"><code>maxPlayersCount</code></a>: <code>null</code></li>
<li><a href="#onlineplayerscount()"><code>onlinePlayersCount</code></a>: <code>null</code></li>
</ul>
returns: 'New ProfileEntry instance with empty/null values defined'
attributes:
@@ -139,7 +152,7 @@ methods:
- name: 'hidePlayersEnabled'
description: |
Whether the player count should be hidden or not in this ProfileEntry.<br>
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault()"><code>getOrDefault(boolean)</code></a>.
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault(boolean)"><code>getOrDefault(boolean)</code></a>.
returns: 'Whether the player count should be hidden or not in this ProfileEntry.'
type:
name: 'NullBool'
@@ -148,7 +161,7 @@ methods:
- name: 'extraPlayersEnabled'
description: |
Whether the extra players feature should be used or not in this ProfileEntry.<br>
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault()"><code>getOrDefault(boolean)</code></a>.
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault(boolean)"><code>getOrDefault(boolean)</code></a>.
returns: 'Whether the extra players feature should be used or not in this ProfileEntry.'
type:
name: 'NullBool'
@@ -157,19 +170,39 @@ methods:
- name: 'maxPlayersEnabled'
description: |
Whether the max players feature should be used or not.<br>
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault()"><code>getOrDefault(boolean)</code></a>.
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault(boolean)"><code>getOrDefault(boolean)</code></a>.
returns: 'Whether the max players feature should be used or not.'
type:
name: 'NullBool'
type: 'object'
link: '../../objects/nullbool/'
- name: 'onlinePlayersEnabled'
description: |
Whether the online players feature should be used or not.<br>
To get the actual boolean value, append <a href="../../objects/nullbool/#getordefault(boolean)"><code>getOrDefault(boolean)</code></a>.
returns: 'Whether the online players feature should be used or not.'
type:
name: 'NullBool'
type: 'object'
link: '../../objects/nullbool/'
- name: 'hidePlayersHoverEnabled'
description: |
Whether the Hover List of online players should be hidden or not.<br>
To get the actual boolean value, use <a href="../../objects/nullbool/#getordefault()"><code>getOrDefault(boolean)</code></a> of the returned <a href="../../objects/nullbool"><code>NullBool</code></a>.<br>
<br>
When true, this option will force the <a href="#players()"><code>players()</code></a> list to be ignored.
returns: 'Whether the Hover List of online players should be hidden or not.'
type:
name: 'NullBool'
type: 'object'
link: '../../objects/nullbool/'
- name: 'extraPlayersCount'
description: 'Gets the currently set number of extra players to use by this ProfileEntry. May be <code>null</code>.'
returns: 'Possibly-null integer number of extra players used by this ProfileEntry.'
description: 'Gets the currently set number of extra players of this ProfileEntry.'
returns: 'The current number of extra players used by this ProfileEntry.'
attributes:
- nullable
type:
name: 'Integer'
name: 'String'
type: 'object'
- name: 'maxPlayersCount'
description: 'Gets the currently set number of max players of this ProfileEntry.'
@@ -177,7 +210,15 @@ methods:
attributes:
- nullable
type:
name: 'Integer'
name: 'String'
type: 'object'
- name: 'onlinePlayersCount'
description: 'Gets the currently set number of online players of this ProfileEntry.'
returns: 'The current number of online players used by this ProfileEntry.'
attributes:
- nullable
type:
name: 'String'
type: 'object'
- name: 'isInvalid'
description: |
+27 -13
View File
@@ -4,7 +4,7 @@ document$.subscribe(async () => {
const repo_stats = document.querySelector('[data-md-component="source"] .md-source__repository');
function loadCodebergInfo(data) {
async function loadCodebergInfo(data) {
const facts = document.createElement("ul");
facts.className = "md-source__facts";
@@ -28,22 +28,36 @@ document$.subscribe(async () => {
repo_stats.appendChild(facts);
}
function loadApiInfo(data) {
async function loadApiInfo(data) {
const codeBlocks = document.querySelectorAll('[data-md-component="api-version"] pre code')
if (codeBlocks === null)
return;
const version = data["version"];
const versionToken = '{apiVersion}';
const codeBlocks = document.querySelectorAll('.md-content pre code');
for(const codeBlock of codeBlocks) {
codeBlock.innerHTML = codeBlock.innerHTML.replace(new RegExp(versionToken, 'g'), version.substring(1));
}
const regex = new RegExp('{apiVersion}', 'g');
codeBlocks.forEach((codeBlock) => {
var walker = document.createTreeWalker(codeBlock, NodeFilter.SHOW_TEXT);
var node;
while (node = walker.nextNode()) {
node.nodeValue = node.nodeValue.replace(regex, version.substring(1));
}
});
}
function loadPluginVersion(data) {
async function loadPluginVersion(data) {
const entries = document.querySelectorAll('code[data-md-component="plugin-version"]');
if(entries === null)
return;
const version = data["version"];
const versionToken = '{version}'
const entries = document.querySelectorAll('.md-content code');
for(const entry of entries) {
entry.innerHTML = entry.innerHTML.replace(new RegExp(versionToken, 'g'), version.substring(1));
}
const regex = new RegExp('{version}', 'g');
entries.forEach((entry) => {
var walker = document.createTreeWalker(entry, NodeFilter.SHOW_TEXT);
var node;
while (node = walker.nextNode()) {
node.nodeValue = node.nodeValue.replace(regex, version.substring(1));
}
})
}
async function fetchApiInfo() {
+11
View File
@@ -44,4 +44,15 @@
.md-source__repository .md-source__facts {
animation: facts .25s ease-in;
}
.md-nav--secondary li.md-nav__item > .md-nav__link {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
.md-banner__inner.md-grid.md-typeset {
text-align: center;
}
+1 -1
View File
@@ -10,7 +10,7 @@ icon: octicons/list-unordered-24
This page lists some examples you may want to use for your proxy or server.
Feel free to suggest additional examples in the `advancedserverlist` category on the [M.O.S.S. Discord Server](https://discord.gg/MyPTjpsgGH){ target="_blank" rel="nofollow" }.
Feel free to suggest additional examples in the `advancedserverlist` category on the [M.O.S.S. Discord Server][discord]{ target="_blank" rel="nofollow" }.
## Table of Contents
+56 -18
View File
@@ -5,7 +5,7 @@ icon: octicons/milestone-24
# Getting Started
This page will explain how to set up AdvancedServerList and make it work for your server.
The guide is designed to be as easy to understand as possible. If you still have problems or questions, join the [M.O.S.S Discord Server](https://discord.gg/MyPTjpsgGH){ target="_blank" rel="nofollow" } for more help.
The guide is designed to be as easy to understand as possible. If you still have problems or questions, join the [M.O.S.S Discord Server][discord]{ target="_blank" rel="nofollow" } for more help.
## 1. Download the plugin { #download-the-plugin }
@@ -41,10 +41,7 @@ AdvancedServerList is available on the following places (Please note the current
</div>
[modrinth]: https://modrinth.com/plugin/advancedserverlist
[codeberg]: https://codeberg.org/Andre601/AdvancedServerList
[spigot]: https://www.spigotmc.org/resources/102910/
[hangar]: https://hangar.papermc.io/Andre_601/AdvancedServerList
The plugin is available for Paper, BungeeCord, Waterfall and Velocity, and has been tested on these platforms. It may support additional forks, but this is not guaranteed.
@@ -109,10 +106,6 @@ The plugin also supports these additional plugins. They are all optional.
</div>
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
[addon]: ../addons/banplugins.md
## 2. Installation { #installation }
@@ -120,11 +113,11 @@ The plugin also supports these additional plugins. They are all optional.
Installing the plugin is as simple as moving the jar file into the `plugins` folder. Just make sure to download the right version of AdvancedServerList for the right platform.
Here is a quick table showing the jar file name with the platforms it is made for:
| Jar file name | Platforms |
|-----------------------------------------------|-----------------------|
| `AdvancedServerList-Paper-{version}.jar` | Paper |
| `AdvancedServerList-BungeeCord-{version}.jar` | BungeeCord, Waterfall |
| `AdvancedServerList-Velocity-{version}.jar` | Velocity |
| 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.
If everything goes well should AdvancedServerList create a folder named `AdvancedServerList` (`advancedserverlist` on Velocity) with additional files and folders inside of it.
@@ -214,12 +207,17 @@ motd:
# This option supports three types of inputs:
#
# 1. Name, including .png extension, pointing to an image located in the plugin's favicons folder.
# 2. URL pointing to an image.*
# 3. Player name, UUID or placeholders returning one of these.*
# 2. "random" to display a random PNG from the favicons folder.
# 3. URL pointing to an image.
# 4. Player name, UUID or placeholders returning one of these.
# https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
#
# * These images are loaded asynchronously, meaning they may not yet be "ready" when AdvancedServerList is done with
# the event, requiring a refresh of the server list by the player to have it shown.
# Note on favicons not showing:
# AdvancedServerList has to create a Favicon object for the Proxy/Server to use which takes time to do so.
# To not delay the Proxy/Server from being displayed (increase the loading time on the player end) is this creation
# done asynchronously for URL/Player name/UUID. This has the downside that the Proxy/Server may be done handling the
# ping before the Favicon is created, causing none to be displayed.
# Note that this won't happen with local favicons, as those are created during the plugin's startup.
#
# Any images above or below 64x64 pixels will be automatically resized to these dimensions.
#
@@ -290,6 +288,7 @@ playerCount:
enabled: false
#
# Set the number that should be added to the online player count to then use as the new max player count.
# Placeholders resolving to numbers can be used here.
#
# Example: Setting this to 1 will result in ${server playersMax} displaying 11 while 10 players are online,
# 9 when 8 are online and so on.
@@ -318,12 +317,37 @@ playerCount:
enabled: false
#
# Set the number that should be used as the new max players count.
# Placeholders resolving to numbers can be used here.
#
# If not present, defaults to 0.
#
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
#
amount: 0
#
# The onlinePlayers feature allows to set a number to use as the online player count to display.
#
# Read more: https://asl.andre601.ch/profiles/#onlineplayers
#
onlinePlayers:
#
# Set whether the onlinePlayers feature should be enabled or not.
# When set to true, the max player count will be set to the 'amount' value.
#
# If not present, defaults to false.
#
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-enabled
#
enabled: false
#
# Set the number that should be used as the new online players count.
# Placeholders resolving to numbers can be used here.
#
# If not present, defaults to current online player count.
#
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-amount
#
amount: 0
```
///
@@ -397,6 +421,14 @@ checkUpdates: true
#
debug: false
#
# Should the "ASL" ASCI art be displayed on plugin startup?
# Setting this to false will hide the banner.
#
# Default: true
#
printBanner: true
#
# Sets how long Favicons should be cached. Value is in minutes with the lowest possible value being 1.
#
@@ -456,6 +488,12 @@ disableDuringMaintenance:
# Default: true
#
maxPlayers: true
#
# Whether the online players feature should be disabled while Maintenance mode is active.
#
# Default: true
#
onlinePlayers: true
#
# DO NOT EDIT!
@@ -463,7 +501,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.
#
config-version: 5
configVersion: 7
```
///
+37
View File
@@ -0,0 +1,37 @@
---
icon: octicons/project-roadmap-24
---
# Tutorials
This page lists tutorials made by the community of AdvancedServerList.
Be aware that any info shown may be outdated.
Can't find a tutorial that exists? Join the [M.O.S.S. Discord][discord]{ target="_blank" rel="nofollow" } and suggest it in `#asl-support` to be added.
## Video Tutorials
Below is a collection of video tutorials made.
/// note
For privacy reasons are only thumbnails of the videos displayed, as otherwise sensitive data would be sent via embedding the videos themself.
you can click the image to be sent to the actual video.
///
### KasaiSora
**Video Language:** :flag_gb: English
[![thumbnail](https://img.youtube.com/vi/9cU0uUWHOO0/0.jpg)](https://youtube.com/watch?v=9cU0uUWHOO0){ target="_blank" rel="nofollow" }
### Ajneb97
**Video Language:** :flag_es: Spanish
[![thumbnail](https://img.youtube.com/vi/rIbljm_4HVI/0.jpg)](https://youtube.com/watch?v=rIbljm_4HVI){ target="_blank" rel="nofollow" }
## Text Tutorials
Text-based tutorials (Forum Posts, Blog Posts, etc).
*No entries yet*
+43
View File
@@ -50,6 +50,12 @@ AdvancedServerList supports the following platforms:
----
A simple guide on how to get started with AdvancedServerList.
----
**Other Pages:**
- [:octicons-project-roadmap-24: Tutorials](getting-started/tutorials.md)
- [:octicons-rel-file-path-24: **Commands**](commands/index.md)
@@ -62,6 +68,14 @@ AdvancedServerList supports the following platforms:
----
Pages containing information about the Server List Profile System and all its available options.
----
**Other Pages:**
- [:octicons-file-code-24: Expressions](profiles/expressions.md)
- [:octicons-pencil-24: Formatting](profiles/formatting.md)
- [:material-percent: Placeholders](profiles/placeholders.md)
- [:octicons-list-unordered-24: **Examples**](examples/index.md)
@@ -74,12 +88,35 @@ AdvancedServerList supports the following platforms:
----
Pages explaining how to migrate from one version of the plugin to another.
----
**Other Pages:**
- Plugins
- [:octicons-arrow-right-24: MiniMOTD](migration/plugins/minimotd.md)
- [:octicons-arrow-right-24: ServerListPlus](migration/plugins/serverlistplus.md)
- Versions
- [:octicons-arrow-right-24: v3.8.0 to v3.9.0](migration/versions/v3.8.0-to-v3.9.0.md)
- [:octicons-arrow-right-24: v3.7.0 to v3.8.0](migration/versions/v3.7.0-to-v3.8.0.md)
- [:octicons-arrow-right-24: < v3.7.0 to v3.7.0](migration/versions/pre-v3.7.0-to-v3.7.0.md)
- [:octicons-arrow-right-24: v1.9.0 to v1.10.0](migration/versions/v1.9.0-to-v1.10.0.md)
- [:octicons-arrow-right-24: v1.5.3 to v1.6.0](migration/versions/v1.5.3-to-v1.6.0.md)
- [:octicons-command-palette-24: **API**](api/index.md)
----
Pages all about the API of AdvancedServerList.
----
**Other Pages:**
- [:octicons-log-24: Changelog](api/changelog.md)
- [:octicons-link-external-24: Javadocs](api/javadocs.md)
- [:simple-codeberg: Source Code](api/source.md)
- [:octicons-file-code-24: Reference](api/reference/index.md)
- [:octicons-plus-circle-24: **Addons**](addons/index.md)
@@ -87,6 +124,12 @@ AdvancedServerList supports the following platforms:
Pages listing 1st-party and 3rd-party add-ons for AdvancedServerList.
----
**Other Pages:**
- [:octicons-stop-24: BanPlugins Addon](addons/banplugins.md)
- [:material-percent: **PlaceholderAPI**](placeholderapi/index.md)
----
+7 -7
View File
@@ -11,13 +11,13 @@ These pages may include important information about the migration process and wh
<div class="grid cards" markdown>
- [**MiniMOTD**](minimotd.md)
- [**MiniMOTD**](plugins/minimotd.md)
----
Migrate from the Plugin [MiniMOTD](https://github.com/jpenilla/MiniMOTD){ target="_blank" rel="nofollow" }
- [**ServerListPlus**](serverlistplus.md)
- [**ServerListPlus**](plugins/serverlistplus.md)
----
@@ -32,31 +32,31 @@ These guides are only for the Server List Profile files, as the config.yml gets
<div class="grid cards" markdown>
- [**v3.8.0 to v3.9.0**](v3_8_0-to-v3_9_0.md)
- [**v3.8.0 to v3.9.0**](versions/v3.8.0-to-v3.9.0.md)
----
Migrate from version 3.8.0 to 3.9.0.
- [**v3.7.0 to v3.8.0**](v3_7_0-to-v3_8_0.md)
- [**v3.7.0 to v3.8.0**](versions/v3.7.0-to-v3.8.0.md)
----
Migrating from version 3.7.0 to 3.8.0.
- [**< v3.7.0 to v3.7.0**](pre-v3_7_0-to-v3_7_0.md)
- [**< v3.7.0 to v3.7.0**](versions/pre-v3.7.0-to-v3.7.0.md)
----
Migrate from any version prior to 3.7.0 to 3.7.0 or newer.
- [**v1.9.0 to v1.10.0**](v1_9_0-to-v1_10_0.md)
- [**v1.9.0 to v1.10.0**](versions/v1.9.0-to-v1.10.0.md)
----
Migrate from version 1.9.0 to 1.10.0.
- [**v1.5.3 to v1.6.0**](v1_5_3-to-v1_6_0.md)
- [**v1.5.3 to v1.6.0**](versions/v1.5.3-to-v1.6.0.md)
----
@@ -11,14 +11,14 @@ Version `4.10.0` added support for migrating your existing `main.conf` configura
## How to Migrate
Execute the command [`/asl migrate minimotd`](../commands/index.md#migrate) to start the migration process. Make sure the `main.conf` file is present in `/plugins/MiniMOTD/` (`minimotd-velocity` on Velocity).
Execute the command [`/asl migrate minimotd`](../../commands/index.md#migrate) to start the migration process. Make sure the `main.conf` file is present in `/plugins/MiniMOTD/` (`minimotd-velocity` on Velocity).
## Example
Below can you find a full example of a `main.conf` file and the corresponding migrated files from AdvancedServerList:
/// tab | :octicons-file-code-24: main.conf
```lighty
```ruby
icon-enabled=true
motd-enabled=true
motds=[
@@ -48,7 +48,7 @@ The following Favicon options get converted into an equivalent one:
## How to Migrate
Execute the command [`/asl migrate serverlistplus`](../commands/index.md#migrate) to start the migration process. Make sure that ServerListPlus is present and enabled.
Execute the command [`/asl migrate serverlistplus`](../../commands/index.md#migrate) to start the migration process. Make sure that ServerListPlus is present and enabled.
## Example
@@ -5,7 +5,7 @@ icon: octicons/arrow-right-24
# < v3.7.0 to v3.7.0
Version 3.7.0 of AdvancedServerList brought significant changes to its conditions system.
Namely, the `conditions` option is now deprecated and planned for removal in a future release of the Plugin, and the new [`condition`](../profiles/index.md#condition) option should now be used instead.
Namely, the `conditions` option is now deprecated and planned for removal in a future release of the Plugin, and the new [`condition`](../../profiles/index.md#condition) option should now be used instead.
## Migration
-2
View File
@@ -6,8 +6,6 @@ icon: material/percent
AdvancedServerList provides support for [PlaceholderAPI] placeholders to be used, while also providing its own set of placeholders.
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
## Own placeholders
The below listed placeholders can be used through PlaceholderAPI in other plugins.
+48 -36
View File
@@ -4,57 +4,69 @@ icon: octicons/pencil-24
# Formatting
All text options, with exception of [`Conditions`](index.md#condition), allow the usage of formatting options using [MiniMessage].
AdvancedServerList utilizes the [MiniMessage] text formatting to allow colors, formatting codes, gradients, etc. for the text options `motd`, `playerCount -> hover` and `playerCount -> text`.
You can find a collection of available tags on the library's [Format] page. Please make sure to see the [Unsupported Formatting](#unsupported-formatting) section below for tags with no support.
/// info | Online Tool
The devs of the Adventure library provide a handy online tool to create the right formatting codes to display the text properly.
You can find the tool at https://webui.advntr.dev/
## Why no legacy colors (`&`/`§` codes) support?
### The tl;dr
MiniMessage tags are overall more readable while also allowing a lot more ways of formatting, with Legacy colors becoming an unreadable mess the more complex your formatting is.
### The long explanation
Legacy colors are a mess to read. This becomes especially evident with gradients using RGB color support.
As an example is here the text `Hello World` made into a Gradient with starting color `#084CFB` and end color `#ADF3FD` both in Legacy Color (Using `&` character) and MiniMessage format:
/// tab | Legacy Color Codes
```
&#084CFBH&#195DFBe&#296DFBl&#3A7EFCl&#4A8FFCo &#6BB0FCW&#7CC1FCo&#8CD2FDr&#9DE2FDl&#ADF3FDd
```
///
## Before starting
Please make sure to surround your text with either single quotes (`'`) or double quotes (`"`).
This avoids possible issues where the YAML parser would treat lines starting with specific characters as special options (i.e. `<` would be treated as a scolar value).
Also, should your text contain single quotes (for example when using `you're`), either surround the text with double quotes, or change the single quote in your text into two single quotes (`you're -> you''re`).
```yaml title="Wrong formatting"
motd:
- <red>This will cause
- <red>Errors
/// tab | MiniMessage
```
```yaml title="Right formatting"
motd:
- "<green>This will be formatted"
- "<green>properly."
<gradient:#084CFB:#ADF3FD>Hello World</gradient>
```
///
## Unsupported options
This becomes even more difficult to work with if you want to add text formatting to only parts of the text.
Assuming you want to make `World` be bold, with legacy colors, you would need to add `&l` before every character of the word, as colors reset any formatting applied. In MiniMessage all you need to do is put `<bold>` before the word and `</bold>` after it.
The following options are **not** supported, no matter what option they are used in:
Another benefit for gradients in particular is, that MiniMessage allows more than one color to be set for the gradient, i.e. you can set three colors for a start, middle and end color.
- Hover Actions (Show text, Show Advancement, etc)
- Click Actions (Run command, Suggest command, etc.)
- Custom Fonts (May work if player already has the resource pack loaded)
## Web Editor
## Colors
The Adventure team offers an [Online Web tool][webviewer]{ target="_blank" rel="nofollow" } that allows you to create the right MiniMessage tags while also having a preview.
Just visit the page and make sure to select `Server List` at the top to have a preview in a server list.
### Default colors
## YAML Formatting
Default colors such as `<red>`, `<green>`, `<aqua>`, etc. may be used in all text options.
It is recommended to always surround your text with single or double quotes. This avoids situations where the YAML parses sees a specific character and treats it as a special YAML feature.
This is especially the case with MiniMessage tags, where `<` can be seen as the start of a so-called scolar value.
### Hex Colors
Should you be using single quotes inside the text itself - i.e. for words such as `you're` - will you either need to surround the text with double quotes, or change the single quote in the word to two single quotes (`you're` becomes `you''re`).
Hexadecimal colors may be used in the [`motd`](index.md#motd) option using the `<#RRGGBB>` format.
## Unsupported Formatting
### Gradients
### Non-functional Tags
Gradients can be created by using `<gradient:<color1>:<color2>>`, replacing `<color1>` with a starting color name or hex color value and `<color2>` with an ending color name or hex color value.
Only the [`motd`](index.md#motd) option may support hex color gradients and in all other options will it be downsampled.
While MiniMessage will parse most, if not all tags, will not all work.
The following list of tags will do nothing, or only work under specific circumstances:
## Formatting
| Tag | Note |
|---------------|------------------------------------------------------------------------------------------------------|
| `<click>` | |
| `<hover>` | |
| `<insertion>` | |
| `<font>` | May work if either a default MC font is used, or the player has a resourcepack with the font loaded. |
| `<selector>` | |
| `<score>` | |
Formatting options (`<bold>`, `<italic>`, etc.) are available for all text options.
### Non-supported RGB
[MiniMessage]: https://docs.adventure.kyori.net/minimessage/index.html
Only the `motd` option supports RGB colors. Every other option allowing MiniMessage format may only support the default colors provided by Minecraft (`<aqua>`, `<yellow>`, etc) with RGB colors being downsampled to their next supported option.
[MiniMessage]: https://docs.advntr.dev/minimessage/index.html
[Format]: https://docs.advntr.dev/minimessage/format.html
[webviewer]: https://webui.advntr.dev/
+21 -7
View File
@@ -91,6 +91,8 @@ motd:
## Motd
<!-- admo:tip Start a line with <code>&lt;center&gt;</code> to have it centered. -->
The `motd` option allows you to alter the "Message of the day" that is being displayed on a server in the multiplayer screen.
Please see the [Formatting](formatting.md) for all supported formatting options.
@@ -119,15 +121,27 @@ motd:
The `favicon` option can be used to define an image to display in the server list.
The Value can be one of three possible options, each being checked for in order:
The Value can be one of the following:
- A URL pointing to an image file. The URL needs to start with `https://` to work.
- The keyword `random`. Setting this will have the plugin randomly select an existing PNG file from its `favicons` folder.
- A filename matching an existing PNG file in the plugin's `favicons` folder. The `.png` extension needs to be included.
- A player name or UUID, or a [placeholder](placeholders.md) that resolves into one.
- A URL pointing to a Image file. The URL needs to start with `https://` for it to work.
- A filename matching a pre-existing file in the `favicons` folder of the Plugin.
- Only PNG files are supported for now and the provided filename needs to end with `.png`
- `random` can be used to have the plugin select a random image from the Favicons folder.
- A player name or UUID.
- `${player name}`, `${player uuid}` or any [placeholder](placeholders.md) that resolves into a player name/UUID can be used.
- Uses [mc-heads.net](https://mc-heads.net) to resolve the Player Name/UUID.
Note that for the name/UUID, the site https://mc-heads.net is being used.
Use the URL option with the `${player uuid}` placeholder if you want to use another service.
/// details | Why is the favicon from URL/Placeholder not showing?
type: question
AdvancedServerList has to create a Favicon instance to use, as the Proxy/Server doesn't directly use PNG images.
This action takes time, so to not unnecessarely delay the Pinged Proxy/Server from showing is this done asynchrnously.
This has the issue that the Proxy/Server may be done with handling the Ping before AdvancedServerList is done creating the Favicon, resulting in no favicon being displayed.
This issue is only present for when using either a URL or a Player name/uuid and not for local favicons, as those are created when the plugin loads.
Favicons *should* display on the second ping, if pinged within the configured favicon cache time (Default: 1 minute).
///
/// details | Example
type: example
+24 -8
View File
@@ -68,6 +68,18 @@ extra:
plugins:
- search
- glightbox
- redirects:
redirect_maps:
# Plugin Migration Pages
'migration/minimotd.md': 'migration/plugins/minimotd.md'
'migration/serverlistplus.md': 'migration/plugins/serverlistplus.md'
#
# Version Migration Pages
'migration/v3_8_0-to-v3_9_0.md': 'migration/versions/v3.8.0-to-v3.9.0.md'
'migration/v3_7_0-to-v3_8_0.md': 'migration/versions/v3.7.0-to-v3.8.0.md'
'migration/pre-v3_7_0-to-v3_7_0.md': 'migration/versions/pre-v3.7.0-to-v3.7.0.md'
'migration/v1_9_0-to-v1_10_0.md': 'migration/versions/v1.9.0-to-v1.10.0.md'
'migration/v1_5_3-to-v1_6_0.md': 'migration/versions/v1.5.3-to-v1.6.0.md'
- pagenav-generator
markdown_extensions:
@@ -84,6 +96,8 @@ markdown_extensions:
- pymdownx.superfences:
- pymdownx.snippets:
base_path: docs/.snippets
auto_append:
- links.md
- pymdownx.blocks.admonition:
types:
- note
@@ -108,7 +122,9 @@ hooks:
nav:
- Home: index.md
- Getting Started: getting-started/index.md
- Getting Started:
- getting-started/index.md
- Tutorials: getting-started/tutorials.md
- Commands: commands/index.md
- Profiles:
- profiles/index.md
@@ -119,14 +135,14 @@ nav:
- Migration:
- migration/index.md
- Other Plugins:
- MiniMOTD: migration/minimotd.md
- ServerListPlus: migration/serverlistplus.md
- MiniMOTD: migration/plugins/minimotd.md
- ServerListPlus: migration/plugins/serverlistplus.md
- AdvancedServerList:
- v3.8.0 to v3.9.0: migration/v3_8_0-to-v3_9_0.md
- v3.7.0 to v3.8.0: migration/v3_7_0-to-v3_8_0.md
- '< v3.7.0 to v3.7.0': migration/pre-v3_7_0-to-v3_7_0.md
- v1.9.0 to v1.10.0: migration/v1_9_0-to-v1_10_0.md
- v1.5.3 to v1.6.0: migration/v1_5_3-to-v1_6_0.md
- v3.8.0 to v3.9.0: migration/versions/v3.8.0-to-v3.9.0.md
- v3.7.0 to v3.8.0: migration/versions/v3.7.0-to-v3.8.0.md
- '< v3.7.0 to v3.7.0': migration/versions/pre-v3.7.0-to-v3.7.0.md
- v1.9.0 to v1.10.0: migration/versions/v1.9.0-to-v1.10.0.md
- v1.5.3 to v1.6.0: migration/versions/v1.5.3-to-v1.6.0.md
- API:
- api/index.md
- Changelog: api/changelog.md
+11 -1
View File
@@ -99,7 +99,7 @@
<dependency>
<groupId>com.viaversion</groupId>
<artifactId>viaversion-api</artifactId>
<version>5.1.1</version>
<version>5.2.1</version>
<scope>provided</scope>
</dependency>
@@ -118,6 +118,16 @@
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
<excludes>
<exclude>char-widths.json.gz</exclude>
</excludes>
</resource>
<resource>
<filtering>false</filtering>
<directory>${project.basedir}/src/main/resources</directory>
<includes>
<include>char-widths.json.gz</include>
</includes>
</resource>
</resources>
<plugins>
@@ -67,18 +67,6 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
@Override
public void onEnable(){
try{
Class.forName("io.papermc.paper.configuration.ConfigurationLoaders");
}catch(ClassNotFoundException ignored){
try{
// Above class only exists since 1.19+. This is a fallback to see if an older version is used.
Class.forName("com.destroystokyo.paper.PaperConfig");
}catch(ClassNotFoundException ex){
printNoPaperWarning();
return;
}
}
this.core = AdvancedServerList.init(this, new PaperPlayerPlaceholders(), new PaperServerPlaceholders(this));
if(getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
@@ -101,9 +89,9 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
@Override
public void loadCommands(){
if(getServer().getCommandMap().register("asl", new CmdAdvancedServerList(this))){
getPluginLogger().info("Registered /advancedserverlist:advancedserverlist");
getPluginLogger().success("Registered <white>/advancedserverlist:advancedserverlist</white>!");
}else{
getPluginLogger().info("Registered /asl:advancedserverlist");
getPluginLogger().success("Registered <white>/asl:advancedserverlist</white>!");
}
}
@@ -225,27 +213,6 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
return players.size();
}
private void printNoPaperWarning(){
getPluginLogger().warn("======================================================================================");
getPluginLogger().warn("THIS SERVER DOES NOT USE PAPER OR A COMPATIBLE FORK!");
getPluginLogger().warn("");
getPluginLogger().warn("AdvancedServerList 3.6.0 has dropped support for Spigot-based servers.");
getPluginLogger().warn("This means that only servers using Paper or a Paper-compatible fork may work.");
getPluginLogger().warn("");
getPluginLogger().warn("Reasons for this removal:");
getPluginLogger().warn(" - Reliance on a different plugin for core functionalities.");
getPluginLogger().warn(" - Bad dependency loading limited to MavenCentral only.");
getPluginLogger().warn("");
getPluginLogger().warn("Please consider switching to Paper or one of the Paper-compatible forks to benefit");
getPluginLogger().warn("from overall performance improvements amongst other things.");
getPluginLogger().warn("");
getPluginLogger().warn("Disabling AdvancedServerList. If you believe this is an error, report it on");
getPluginLogger().warn("Codeberg: https://codeberg.org/Andre601/AdvancedServerList");
getPluginLogger().warn("======================================================================================");
Bukkit.getPluginManager().disablePlugin(this);
}
private String getNewVersion(){
ServerBuildInfo info = ServerBuildInfo.buildInfo();
@@ -255,7 +222,7 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
OptionalInt build = info.buildNumber();
if(build.isEmpty())
return String.format("%s (%s, Version: %s)", name, id, version);
return String.format("%s (ID: %s, Version: %s)", name, id, version);
return String.format("%s (ID: %s, Version: %s, Build: %d)", name, id, version, build.getAsInt());
}
@@ -48,5 +48,20 @@ public class LoadEvent implements Listener{
// Load currently loaded worlds into the WorldCache
Bukkit.getWorlds().forEach(world -> plugin.getWorldCache().addWorld(world));
// Print a warning if server load was after a reload.
if(event.getType() != ServerLoadEvent.LoadType.RELOAD)
return;
plugin.getPluginLogger().warn("======================================================================================");
plugin.getPluginLogger().warn("SERVER RELOAD DETECTED!");
plugin.getPluginLogger().warn("");
plugin.getPluginLogger().warn("A server reload has been detected by AdvancedServerList, meaning either the /reload");
plugin.getPluginLogger().warn("command or Bukkit.reload() was executed.");
plugin.getPluginLogger().warn("");
plugin.getPluginLogger().warn("YOU WILL GET NO SUPPORT FOR THE PLUGIN FOR ANY ISSUES YOU ENCOUNTER AFTER A SERVER");
plugin.getPluginLogger().warn("RELOAD!");
plugin.getPluginLogger().warn("ALWAYS RESTART YOUR SERVER. NEVER RELOAD IT!");
plugin.getPluginLogger().warn("======================================================================================");
}
}
@@ -98,14 +98,24 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
@Override
public void setPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
try{
event.getListedPlayers();
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent$ListedPlayerInfo");
setListedPlayers(lines, player, server);
}catch(NoSuchMethodError ex){
}catch(ClassNotFoundException ex){
// Version before latest 1.20.6 builds(?)
setPlayerSample(lines, player, server);
}
}
@Override
public void setPlayersHidden(){
try{
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent$ListedPlayerInfo");
clearListedPlayers();
}catch(ClassNotFoundException ex){
clearPlayerSample();
}
}
@Override
public void setFavicon(CachedServerIcon favicon){
event.setServerIcon(favicon);
@@ -184,8 +194,12 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
return new PaperServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
}
private void setListedPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
private void clearListedPlayers(){
event.getListedPlayers().clear();
}
private void setListedPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
clearListedPlayers();
List<PaperServerListPingEvent.ListedPlayerInfo> playerList = getPlayerList(lines, player, server,
text -> new PaperServerListPingEvent.ListedPlayerInfo(text, UUID.randomUUID()));
@@ -193,8 +207,13 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
}
@SuppressWarnings({"Deprecation", "removal"})
private void setPlayerSample(List<String> lines, PaperPlayerImpl player, GenericServer server){
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);
@@ -26,19 +26,18 @@
package ch.andre601.advancedserverlist.paper.logging;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.paper.PaperCore;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
public class PaperLogger implements PluginLogger{
private final PaperCore plugin;
private final Logger logger;
private final ComponentLogger logger;
public PaperLogger(PaperCore plugin){
this.plugin = plugin;
this.logger = plugin.getLogger();
this.logger = plugin.getComponentLogger();
}
@Override
@@ -55,21 +54,21 @@ public class PaperLogger implements PluginLogger{
@Override
public void info(String msg, Object... args){
logger.info(String.format(msg, args));
logger.info(ComponentParser.textFormatted("<grey>" + msg, args).toComponent());
}
@Override
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
logger.warn(ComponentParser.textFormatted("<yellow>" + msg, args).toComponent());
}
@Override
public void warn(String msg, Throwable throwable){
logger.log(Level.WARNING, msg, throwable);
logger.warn(ComponentParser.text("<yellow>" + msg).toComponent(), throwable);
}
@Override
public void warn(String msg, Throwable throwable, Object... args){
logger.log(Level.WARNING, String.format(msg, args), throwable);
logger.warn(ComponentParser.textFormatted("<yellow>" + msg, args).toComponent(), throwable);
}
}
@@ -36,7 +36,7 @@ public class PaperPlayerImpl implements BukkitPlayer{
private final OfflinePlayer player;
private final String name;
private int protocol;
private final int protocol;
private final UUID uuid;
private boolean playedBefore = false;
@@ -46,6 +46,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class PAPIPlaceholders extends PlaceholderExpansion{
@@ -114,9 +115,9 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
BukkitServer finalServer = new PaperServerImpl(plugin.getWorldCache().worlds(), online, max, host);
return switch(identifier.toLowerCase(Locale.ROOT)){
case "motd" -> getOption(entry.motd(), pl, player, finalServer);
case "motd" -> getOption(entry.motd(), pl, player, finalServer, true);
case "favicon" -> getOption(entry.favicon(), pl, player, finalServer);
case "playercount_hover" -> getOption(entry.players(), pl, player, finalServer);
case "playercount_hover" -> getOption(entry.players(), pl, player, finalServer, false);
case "playercount_text" -> getOption(entry.playerCountText(), pl, player, finalServer);
case "playercount_extraplayers" -> extraPlayers == null ? "null" : String.valueOf(extraPlayers);
case "playercount_maxplayers" -> maxPlayers == null ? "null" : String.valueOf(maxPlayers);
@@ -136,14 +137,23 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
}
private String getOption(String str, Player pl, BukkitPlayer player, BukkitServer server){
return getOption(Collections.singletonList(str), pl, player, server);
return getOption(Collections.singletonList(str), pl, player, server, false);
}
private String getOption(List<String> list, Player pl, BukkitPlayer player, BukkitServer server){
return ComponentParser.list(list)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
.toString();
private String getOption(List<String> list, Player pl, BukkitPlayer player, BukkitServer server, boolean isMotd){
return list.stream()
.map(line -> ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
.modifyText(text -> {
if(isMotd)
return plugin.getCore().getTextCenterUtil().getCenteredText(text);
return text;
})
.toString()
)
.collect(Collectors.joining("\n"));
}
private Integer parseNumberOption(String option, Player pl, BukkitPlayer player, BukkitServer server){
+1 -10
View File
@@ -5,7 +5,7 @@ description: '${plugin.description}'
main: 'ch.andre601.advancedserverlist.paper.PaperCore'
api-version: '1.19'
api-version: '1.20'
folia-supported: true
@@ -24,15 +24,6 @@ dependencies:
load: BEFORE
required: false
# The below stuff is NOT used by Paper plugin.
commands:
advancedserverlist:
description: 'Main command of AdvancedServerList'
usage: '/<command> [help|reload]'
aliases:
- 'asl'
permission: 'advancedserverlist.admin'
# This is actually supported(?)
permissions:
advancedserverlist.*:
-58
View File
@@ -1,58 +0,0 @@
#
# This file is kept for Folia support.
#
name: 'AdvancedServerList'
author: 'Andre_601'
version: '${plugin.version}'
description: '${plugin.description}'
main: 'ch.andre601.advancedserverlist.paper.PaperCore'
api-version: '1.19'
folia-supported: true
libraries:
- 'org.spongepowered:configurate-yaml:4.1.2'
- 'net.kyori:adventure-text-serializer-legacy:4.12.0'
- 'com.squareup.okhttp3:okhttp:4.10.0'
softdepend:
- 'PlaceholderAPI'
- 'Maintenance'
commands:
advancedserverlist:
description: 'Main command of AdvancedServerList'
usage: '/<command> [help|reload|clearCache]'
aliases:
- 'asl'
permission: 'advancedserverlist.admin'
permissions:
advancedserverlist.*:
description: 'Grants access to all permissions'
default: op
children:
- 'advancedserverlist.admin'
advancedserverlist.admin:
description: 'Grants access to all permissions'
default: op
children:
- 'advancedserverlist.command.*'
advancedserverlist.command.*:
description: 'Grants access to all commands'
default: op
children:
- 'advancedserverlist.command.help'
- 'advancedserverlist.command.reload'
advancedserverlist.command.help:
description: 'Grants access to /asl help'
default: op
advancedserverlist.command.reload:
description: 'Grants access to /asl reload'
default: op
advancedserverlist.command.clearcache:
description: 'Clears the Player and Favicon cache'
default: op
+5 -5
View File
@@ -37,14 +37,14 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plugin.version>5.1.0</plugin.version>
<plugin.version>5.4.0</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<api.version>4.0.0</api.version>
<api.version>4.1.0</api.version>
<dependency.adventure-api>4.17.0</dependency.adventure-api>
<dependency.adventure-text-minimessage>4.17.0</dependency.adventure-text-minimessage>
<dependency.adventure-text-serializer-legacy>4.17.0</dependency.adventure-text-serializer-legacy>
<dependency.adventure-api>4.18.0</dependency.adventure-api>
<dependency.adventure-text-minimessage>4.18.0</dependency.adventure-text-minimessage>
<dependency.adventure-text-serializer-legacy>4.18.0</dependency.adventure-text-serializer-legacy>
<dependency.adventure-platform-bungeecord>4.3.4</dependency.adventure-platform-bungeecord>
<dependency.configurate-yaml>4.1.2</dependency.configurate-yaml>
+13 -1
View File
@@ -1,11 +1,23 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base", "group:allNonMajor"],
"dependencyDashboard": false,
"labels": ["PR Type/Dependency Update"],
"ignoreDeps": [
"ch.andre601.advancedserverlist:parent",
"ch.andre601.advancedserverlist:core"
],
"packageRules": [
{
"description": "Automerge non-major updates",
"matchUpdateTypes": [
"minor",
"patch",
"pin",
"digest"
],
"automerge": true
},
{
"description": "Use Jitpack registry for various Libs",
"matchPackageNames": [
@@ -37,7 +49,7 @@
"io.papermc.paper:paper-api"
],
"registryUrls": [
"https://papermc.io/repo/repository/maven-public"
"https://repo.papermc.io/repository/maven-public"
]
},
{
+2 -1
View File
@@ -1,3 +1,4 @@
mkdocs-material==9.5.47
mkdocs-material==9.5.49
mkdocs-glightbox==0.4.0
mkdocs-redirects==1.2.2
git+https://github.com/Andre601/mkdocs-pagenav-generator
+17 -1
View File
@@ -48,6 +48,10 @@
<id>velocity-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>repo-sayandevelopment</id>
<url>https://repo.sayandev.org/snapshots</url>
</repository>
</repositories>
<dependencies>
@@ -68,7 +72,7 @@
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>3.1.2-SNAPSHOT</version>
<version>3.4.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -95,6 +99,18 @@
<version>2.9.0-4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-api</artifactId>
<version>1.6.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sayandev</groupId>
<artifactId>sayanvanish-proxy-velocity</artifactId>
<version>1.6.1</version>
<scope>provided</scope>
</dependency>
<!-- Other -->
<dependency>
@@ -51,10 +51,10 @@ import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.scheduler.ScheduledTask;
import com.velocitypowered.api.util.Favicon;
import de.myzelyam.api.vanish.VelocityVanishAPI;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import org.bstats.charts.SimplePie;
import org.bstats.velocity.Metrics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sayandev.sayanvanish.velocity.api.SayanVanishVelocityAPI;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
@@ -67,10 +67,11 @@ import java.util.concurrent.TimeUnit;
public class VelocityCore implements PluginCore<Favicon>{
private final Logger logger = LoggerFactory.getLogger("AdvancedServerList");
private final Map<String, ServerPing> fetchedServers = new ConcurrentHashMap<>();
private final PluginLogger pluginLogger;
private final ComponentLogger logger;
private final ProxyServer proxy;
private final Path path;
private final Metrics.Factory metrics;
@@ -84,7 +85,9 @@ public class VelocityCore implements PluginCore<Favicon>{
@Inject
public VelocityCore(ProxyServer proxy, @DataDirectory Path path, Metrics.Factory metrics){
this.pluginLogger = new VelocityLogger(this, this.logger);
ComponentLogger logger = ComponentLogger.logger("AdvancedServerList");
this.pluginLogger = new VelocityLogger(this, logger);
this.logger = logger;
this.proxy = proxy;
this.path = path;
@@ -112,6 +115,7 @@ public class VelocityCore implements PluginCore<Favicon>{
.build();
getProxy().getCommandManager().register(command, new CmdAdvancedServerList(this));
getPluginLogger().success("Registered <white>/advancedserverlist</white>!");
}
@Override
@@ -223,6 +227,9 @@ public class VelocityCore implements PluginCore<Favicon>{
// Exclude players when PremiumVanish is enabled and player is hidden.
if(getProxy().getPluginManager().isLoaded("premiumvanish")){
players.removeIf(VelocityVanishAPI::isInvisible);
}else // Do the same if SayanVanish is enabled.
if(getProxy().getPluginManager().isLoaded("sayanvanish")){
players.removeIf(player -> SayanVanishVelocityAPI.getInstance().isVanished(player.getUniqueId()));
}
return players.size();
@@ -119,6 +119,11 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
builder.clearSamplePlayers().samplePlayers(players);
}
@Override
public void setPlayersHidden(){
builder.clearSamplePlayers();
}
@Override
public void setFavicon(Favicon favicon){
builder.favicon(favicon);
@@ -26,15 +26,16 @@
package ch.andre601.advancedserverlist.velocity.logging;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import org.slf4j.Logger;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
public class VelocityLogger implements PluginLogger{
private final VelocityCore plugin;
private final Logger logger;
private final ComponentLogger logger;
public VelocityLogger(VelocityCore plugin, Logger logger){
public VelocityLogger(VelocityCore plugin, ComponentLogger logger){
this.plugin = plugin;
this.logger = logger;
}
@@ -53,21 +54,21 @@ public class VelocityLogger implements PluginLogger{
@Override
public void info(String msg, Object... args){
logger.info(String.format(msg, args));
logger.info(ComponentParser.textFormatted("<grey>" + msg, args).toComponent());
}
@Override
public void warn(String msg, Object... args){
logger.warn(String.format(msg, args));
logger.warn(ComponentParser.textFormatted(msg, args).toComponent());
}
@Override
public void warn(String msg, Throwable throwable){
logger.warn(msg, throwable);
logger.warn(ComponentParser.text(msg).toComponent(), throwable);
}
@Override
public void warn(String msg, Throwable throwable, Object... args){
logger.warn(String.format(msg, args), throwable);
logger.warn(ComponentParser.textFormatted(msg, args).toComponent(), throwable);
}
}
+1 -1
View File
@@ -52,7 +52,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.12</version>
<version>1.5.15</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -130,7 +130,7 @@ public class HangarVersionUploader{
Platform.VELOCITY, velocityDependencies
),
Map.of(
Platform.PAPER, List.of("1.20.x", "1.21"),
Platform.PAPER, List.of("1.20.x", "1.21.x"),
Platform.WATERFALL, List.of("1.19.x", "1.20.x", "1.21"),
Platform.VELOCITY, Collections.singletonList("3.2")
),
@@ -55,7 +55,8 @@ public class ModrinthVersionUploader{
PlatformInfo.VELOCITY
);
private final List<String> versions = List.of(
"1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6", "1.21"
"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"
);
private final ModrinthAPI api;