diff --git a/build.gradle b/build.gradle index d677eaa..6a8a967 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ repositories { maven { url = 'https://repo.william278.net/velocity/' } maven { url = 'https://repo.papermc.io/repository/maven-public/' } maven { url = 'https://repo.william278.net/releases/' } + maven { url = 'https://repo.william278.net/snapshots/' } maven { url = 'https://jitpack.io/' } maven { url = 'https://repo.minebench.de/' } } @@ -50,6 +51,7 @@ dependencies { implementation 'de.exlll:configlib-yaml:4.5.0' implementation 'org.apache.commons:commons-jexl3:3.4.0' implementation 'net.jodah:expiringmap:0.5.11' + implementation("net.william278:velocityscoreboardapi:1.0.0-b2d9518") annotationProcessor 'org.projectlombok:lombok:1.18.34' } diff --git a/docs/Animations.md b/docs/Animations.md index 7afb23f..caf9e43 100644 --- a/docs/Animations.md +++ b/docs/Animations.md @@ -11,9 +11,9 @@ To add additional frames of animation to a header format for a [server group](se ```yaml headers: - - '&rainbow&Running Velocitab by William278' - - '&rainbow:10&Running Velocitab by William278' - - '&rainbow:20&Running Velocitab by William278' + - 'Running Velocitab by William278 & AlexDev_' + - 'Running Velocitab by William278 & AlexDev_' + - 'Running Velocitab by William278 & AlexDev_' ``` @@ -35,47 +35,47 @@ Wondering how to make something like the above example? Here's how! This example Please note this is not a complete tab_groups file; you will need to add the relevant sections to the correct part in your own Velocitab `tab_groups.yml`. ```yaml headers: - - '&rainbow&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:2&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:4&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:6&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:8&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:10&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:12&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:14&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:16&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:18&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:20&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:22&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:24&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:26&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:28&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:30&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:32&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:34&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:36&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:38&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:40&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:42&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:44&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:46&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:48&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:50&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:52&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:54&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:56&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:58&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' - - '&rainbow:60&Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' + - 'Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n' footers: - | - \n&7For Velocity proxy servers: - bd96a-#6cffa9&https://modrinth.com/plugin/velocitab - bd96a-#6cffa9&https://william278.net/project/veloictab' -format: 'ϧ-#fff&[%server%] &f%username%' + \nFor Velocity proxy servers: + https://modrinth.com/plugin/velocitab + https://william278.net/project/veloictab' +format: '[%server%] &f%username%' header_footer_update_rate: 200 ``` In config.yml ```yaml -formatter: MINEDOWN +formatter: MINIMESSAGE ``` diff --git a/docs/Config-File.md b/docs/Config-File.md index 6a5e8d7..de47b82 100644 --- a/docs/Config-File.md +++ b/docs/Config-File.md @@ -19,8 +19,8 @@ check_for_updates: true remove_nametags: true # Whether to disable header and footer if they are empty and let backend servers handle them. disable_header_footer_if_empty: true -# Which text formatter to use (MINEDOWN, MINIMESSAGE, or LEGACY) -formatter: MINEDOWN +# Which text formatter to use (MINIMESSAGE, MINEDOWN or LEGACY) +formatter: MINIMESSAGE # All servers which are not in other groups will be put in the fallback group. # "false" will exclude them from Velocitab. fallback_enabled: true @@ -56,7 +56,7 @@ enable_plugin_message_api: true # • If you supply a url with a 'bug_report' label, it will be shown if the player is disconnected. # • Specify a set of server groups each URL should be sent on. Use '*' to show a URL to all groups. server_links: - - label: '�fb9a&About Velocitab' + - label: '<#00fb9a>About Velocitab' url: 'https://william278.net/project/velocitab' groups: - '*' @@ -79,29 +79,30 @@ server_links: # ┗╸ Documentation: https://william278.net/docs/velocitab groups: -- name: default - headers: - - '&rainbow&Running Velocitab by William278' - footers: - - '[There are currently %players_online%/%max_players_online% players online](gray)' - format: '&7[%server%] &f%prefix%%username%' - nametag: - prefix: '&f%prefix%' - suffix: '&f%suffix%' - servers: - - ^lobby[^ ]* - - survival - - creative - - minigames - - skyblock - - prison - sorting_placeholders: - - '%role_weight%' - - '%username_lower%' - collisions: false - header_footer_update_rate: 1000 - placeholder_update_rate: 1000 - only_list_players_in_same_server: false + - name: default + headers: + - Running Velocitab by William278 & AlexDev_ + footers: + - There are currently %players_online%/%max_players_online% players online + format: [%server%] %prefix%%username% + nametag: + prefix: %prefix% + suffix: %suffix% + servers: + - skyblock + - minigames + - survival + - lobby + - prison + - creative + - hub + sorting_placeholders: + - '%role_weight%' + - '%username_lower%' + collisions: false + header_footer_update_rate: 1000 + placeholder_update_rate: 1000 + only_list_players_in_same_server: false ``` diff --git a/docs/Formatting.md b/docs/Formatting.md index ca0d106..9425af8 100644 --- a/docs/Formatting.md +++ b/docs/Formatting.md @@ -1,12 +1,14 @@ -Velocitab supports the full range of modern color formatting, including RGB colors and gradients. Both MineDown (_default_), MiniMessage and Legacy formatting are supported. To change which formatter is being used, change the `formatter` value in `config.yml` to `MINEDOWN`, `MINIMESSAGE` or `LEGACY` respectively. +Velocitab supports the full range of modern color formatting, including RGB colors and gradients. Both MiniMessage (_default_), MineDown and Legacy formatting are supported. To change which formatter is being used, change the `formatter` value in `config.yml` to `MINEDOWN`, `MINIMESSAGE` or `LEGACY` respectively. Formatting is applied on header, footer and player text for each server group, and is applied after [[Placeholders]] have been inserted. -## MineDown syntax reference -MineDown is the default formatter type, enabled by setting `formatter` to `MINEDOWN` in `config.yml`. See the [MineDown Syntax Reference](https://github.com/WiIIiam278/MineDown) on GitHub for the specification of how to format text with it. ## MiniMessage syntax reference -MiniMessage formatting can be enabled by setting `formatter` to `MINIMESSAGE` in `config.yml`. See the [MiniMessage Syntax Reference](https://docs.advntr.dev/minimessage/format.html) on the Adventure Docs for how to format text with it. Using MiniMessage as the formatter also allows compatibility for using MiniPlaceholders in text. +MiniMessage is the default formatter type, enabled by setting `formatter` to `MINIMESSAGE` in `config.yml`. See the [MiniMessage Syntax Reference](https://docs.advntr.dev/minimessage/format.html) on the Adventure Docs for how to format text with it. Using MiniMessage as the formatter also allows compatibility for using MiniPlaceholders in text. + +## MineDown syntax reference +MineDown formatting can be enabled by setting `formatter` to `MINEDOWN` in `config.yml`. See the [MineDown Syntax Reference](https://github.com/WiIIiam278/MineDown) on GitHub for the specification of how to format text with it. + ## Legacy formatting > **Warning:** The option for legacy formatting is provided only for backwards compatibility with other plugins. Please consider using the MineDown or MiniMessage options instead! diff --git a/docs/Nametags.md b/docs/Nametags.md index 590d221..01d183b 100644 --- a/docs/Nametags.md +++ b/docs/Nametags.md @@ -41,3 +41,12 @@ Nametags must adhere to the following restrictions: * Velocitab determines which color to use here based on the last color format used in the configured prefix (displayed before their name), downsampled from RGB if necessary. * To control this, simply set the prefix format to end with a valid [team color](https://wiki.vg/Text_formatting#Colors) you want to use (e.g. `&4` for dark_red in Minedown formatting). * Nametags cannot contain newlines (must be on a single line). + +## Bypassing formatting restrictions +UnlimitedNameTags is a spigot plugin that lets you create nametags with unlimited length and lines. +You can use rgb colors and gradients in usernames. +In order to use this plugin you need to disable the nametag feature in Velocitab by setting `remove_nametags` to `true` in the [`config.yml` file](config-file) and put an empty nametag (empty prefix & suffix) in the [`tab_groups.yml` file](Server-Groups.md). +You can find the plugin on [BuiltByBit](https://builtbybit.com/resources/unlimitednametags.46172/?ref=38685) and on [SpigotMC](https://www.spigotmc.org/resources/unlimitednametags.117526/). + +![UnlimitedNameTags](https://i.imgur.com/VvHtqlY.gif) + diff --git a/docs/Server-Groups.md b/docs/Server-Groups.md index 1088993..73c2c28 100644 --- a/docs/Server-Groups.md +++ b/docs/Server-Groups.md @@ -17,9 +17,9 @@ rate to use for the group. ```yaml headers: - - '&rainbow&Running Velocitab by William278' + - 'Running Velocitab by William278 & AlexDev_' footers: - - '[There are currently %players_online%/%max_players_online% players online](gray)' + - 'There are currently %players_online%/%max_players_online% players online' ``` @@ -35,7 +35,7 @@ information. Example of format ```yaml - format: '&7[%server%] &f%prefix%%username%' + format: '[%server%] %prefix%%username%' ``` @@ -51,8 +51,8 @@ Player formats may only utilize one line. ```yaml nametag: - prefix: '&f%prefix%' - suffix: '&f%suffix%' + prefix: '%prefix%' + suffix: '%suffix%' ``` @@ -148,10 +148,10 @@ placeholders in the TAB list will update. The default is 1000 milliseconds (1 se groups: - name: lobbies headers: - - '&rainbow&Running Velocitab by William278 on Lobbies!' + - 'Running Velocitab by William278 & AlexDev_ on Lobbies!' footers: - - '[There are currently %players_online%/%max_players_online% players online](gray)' - format: '&7[%server%] &f%prefix%%username%' + - 'There are currently %players_online%/%max_players_online% players online' + format: '[%server%] %prefix%%username%' servers: - lobby - hub @@ -165,10 +165,10 @@ groups: placeholder_update_rate: 1000 - name: creative headers: - - '&rainbow&Running Velocitab by William278 on Creative!' + - 'Running Velocitab by William278 & AlexDev_ on Creative!' footers: - - '[There are currently %players_online%/%max_players_online% players online](gray)' - format: '&7[%server%] &f%prefix%%username%' + - 'There are currently %players_online%/%max_players_online% players online' + format: '[%server%] %prefix%%username%' servers: - creative sorting_placeholders: @@ -178,10 +178,10 @@ groups: placeholder_update_rate: 1000 - name: survival headers: - - '&rainbow&Running Velocitab by William278 on Survival!' + - 'Running Velocitab by William278 & AlexDev_ on Survival!' footers: - - '[There are currently %players_online%/%max_players_online% players online](gray)' - format: '&7[%server%] &f%prefix%%username%' + - 'There are currently %players_online%/%max_players_online% players online' + format: '[%server%] %prefix%%username%' servers: - survival sorting_placeholders: diff --git a/src/main/java/net/william278/velocitab/Velocitab.java b/src/main/java/net/william278/velocitab/Velocitab.java index b9b12ea..74bba41 100644 --- a/src/main/java/net/william278/velocitab/Velocitab.java +++ b/src/main/java/net/william278/velocitab/Velocitab.java @@ -114,7 +114,6 @@ public class Velocitab implements ConfigProvider, ScoreboardProvider, LoggerProv @Subscribe public void onProxyShutdown(@NotNull ProxyShutdownEvent event) { -// server.getScheduler().tasksByPlugin(this).forEach(ScheduledTask::cancel); disableScoreboardManager(); getLuckPermsHook().ifPresent(LuckPermsHook::closeEvent); getMiniPlaceholdersHook().ifPresent(MiniPlaceholdersHook::unregisterExpansion); diff --git a/src/main/java/net/william278/velocitab/config/Formatter.java b/src/main/java/net/william278/velocitab/config/Formatter.java index 6d93121..9948cdb 100644 --- a/src/main/java/net/william278/velocitab/config/Formatter.java +++ b/src/main/java/net/william278/velocitab/config/Formatter.java @@ -48,8 +48,8 @@ public enum Formatter { ), MINIMESSAGE( (text, player, viewer, plugin) -> plugin.getMiniPlaceholdersHook() - .filter(hook -> viewer != null) - .map(hook -> hook.format(text, player.getPlayer(), viewer.getPlayer())) + .filter(hook -> player != null) + .map(hook -> hook.format(text, player.getPlayer(), viewer == null ? null : viewer.getPlayer())) .orElse(MiniMessage.miniMessage().deserialize(text)), (text) -> MiniMessage.miniMessage().escapeTags(text), "MiniMessage", diff --git a/src/main/java/net/william278/velocitab/config/Placeholder.java b/src/main/java/net/william278/velocitab/config/Placeholder.java index b01571b..1fb3321 100644 --- a/src/main/java/net/william278/velocitab/config/Placeholder.java +++ b/src/main/java/net/william278/velocitab/config/Placeholder.java @@ -22,8 +22,8 @@ package net.william278.velocitab.config; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.server.RegisteredServer; import it.unimi.dsi.fastutil.Pair; -import net.kyori.adventure.text.minimessage.MiniMessage; import net.william278.velocitab.Velocitab; +import net.william278.velocitab.hook.miniconditions.MiniConditionManager; import net.william278.velocitab.player.TabPlayer; import net.william278.velocitab.tab.Nametag; import org.apache.commons.lang3.StringUtils; @@ -114,13 +114,17 @@ public enum Placeholder { .orElse(getPlaceholderFallback(plugin, "%luckperms_meta_" + param + "%"))); private final static Pattern VELOCITAB_PATTERN = Pattern.compile(""); + private final static Pattern TEST = Pattern.compile("<.*?>"); + private final static Pattern CONDITION_REPLACER = Pattern.compile(""); private final static String DELIMITER = ":::"; - private final static String REL_SUBSTITUTE = "-REL-"; - public final static Map SYMBOL_SUBSTITUTES = Map.of( - "<", "-COND-1", - ">", "-COND-2" + private final static Map SYMBOL_SUBSTITUTES = Map.of( + "<", "*LESS*", + ">", "*GREATER*" + ); + private final static Map SYMBOL_SUBSTITUTES_2 = Map.of( + "*LESS*", "*LESS2*", + "*GREATER*", "*GREATER2*" ); /** @@ -163,44 +167,65 @@ public enum Placeholder { format = result.right(); format = replacePlaceholders(format, plugin, player); - if (result.left()) { - format = format.replace(REL_SUBSTITUTE, "%"); - } - return format; } private static Pair processRelationalPlaceholders(@NotNull String format, @NotNull Velocitab plugin) { boolean foundRelational = false; - if (format.contains(" entry : MiniConditionManager.REPLACE.entrySet()) { + condition = condition.replace(entry.getKey(), entry.getValue()); + } + for (Map.Entry entry : MiniConditionManager.REPLACE_2.entrySet()) { + condition = condition.replace(entry.getValue(), entry.getKey()); + } + format = format.replace(search, condition); + } + + final Matcher testMatcher = TEST.matcher(format); + while (testMatcher.find()) { + if(testMatcher.group().startsWith(" entry : SYMBOL_SUBSTITUTES.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + } + format = format.replace(second.group(), s); + } continue; } + String s = testMatcher.group(); + for (Map.Entry entry : SYMBOL_SUBSTITUTES.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + } + format = format.replace(testMatcher.group(), s); + } + + final Matcher velocitabRelationalMatcher = VELOCITAB_PATTERN.matcher(format); + while (velocitabRelationalMatcher.find()) { foundRelational = true; final String relationalPlaceholder = velocitabRelationalMatcher.group().substring(1, velocitabRelationalMatcher.group().length() - 1); - final String fixedString = replaceSymbols(relationalPlaceholder); + String fixedString = relationalPlaceholder; + for (Map.Entry entry : SYMBOL_SUBSTITUTES_2.entrySet()) { + fixedString = fixedString.replace(entry.getKey(), entry.getValue()); + } format = format.replace(relationalPlaceholder, fixedString); } - format = processConditionalPlaceholders(format); + for (Map.Entry entry : SYMBOL_SUBSTITUTES.entrySet()) { + format = format.replace(entry.getValue(), entry.getKey()); + } + } return Pair.of(foundRelational, format); } - @NotNull - private static String processConditionalPlaceholders(@NotNull String format) { - final Matcher conditionalMatcher = CONDITIONAL_PATTERN.matcher(format); - while (conditionalMatcher.find()) { - String conditionalPlaceholder = conditionalMatcher.group(); - conditionalPlaceholder = conditionalPlaceholder.substring(1, conditionalPlaceholder.length() - 1); - final String fixedString = replaceSymbols(conditionalPlaceholder); - format = format.replace(conditionalPlaceholder, fixedString); - } - return format; - } - @NotNull private static String replacePlaceholders(@NotNull String format, @NotNull Velocitab plugin, @Nullable TabPlayer player) { for (Placeholder placeholder : values()) { @@ -219,16 +244,6 @@ public enum Placeholder { return format; } - @NotNull - private static String replaceSymbols(@NotNull String input) { - String fixedString = input.replace("%", REL_SUBSTITUTE); - fixedString = MiniMessage.miniMessage().serialize(Formatter.LEGACY.deserialize(fixedString)); - for (Map.Entry entry : SYMBOL_SUBSTITUTES.entrySet()) { - fixedString = fixedString.replace(entry.getKey(), entry.getValue()); - } - return fixedString; - } - public static CompletableFuture replace(@NotNull String format, @NotNull Velocitab plugin, @NotNull TabPlayer player) { diff --git a/src/main/java/net/william278/velocitab/config/ServerUrl.java b/src/main/java/net/william278/velocitab/config/ServerUrl.java index c4274a3..b4c519f 100644 --- a/src/main/java/net/william278/velocitab/config/ServerUrl.java +++ b/src/main/java/net/william278/velocitab/config/ServerUrl.java @@ -19,7 +19,6 @@ package net.william278.velocitab.config; -import com.google.common.collect.Lists; import com.velocitypowered.api.util.ServerLink; import net.william278.velocitab.Velocitab; import net.william278.velocitab.player.TabPlayer; diff --git a/src/main/java/net/william278/velocitab/config/Settings.java b/src/main/java/net/william278/velocitab/config/Settings.java index 7fb0587..3e11c17 100644 --- a/src/main/java/net/william278/velocitab/config/Settings.java +++ b/src/main/java/net/william278/velocitab/config/Settings.java @@ -54,8 +54,8 @@ public class Settings implements ConfigValidator { @Comment("Whether to disable header and footer if they are empty and let backend servers handle them.") private boolean disableHeaderFooterIfEmpty = true; - @Comment("Which text formatter to use (MINEDOWN, MINIMESSAGE, or LEGACY)") - private Formatter formatter = Formatter.MINEDOWN; + @Comment("Which text formatter to use (MINIMESSAGE, MINEDOWN or LEGACY)") + private Formatter formatter = Formatter.MINIMESSAGE; @Comment("All servers which are not in other groups will be put in the fallback group." + "\n\"false\" will exclude them from Velocitab.") @@ -104,7 +104,7 @@ public class Settings implements ConfigValidator { "• Specify a set of server groups each URL should be sent on. Use '*' to show a URL to all groups."}) private List serverLinks = List.of( new ServerUrl( - "�fb9a&About Velocitab", + "<#00fb9a>About Velocitab", "https://william278.net/project/velocitab" ) ); diff --git a/src/main/java/net/william278/velocitab/config/TabGroups.java b/src/main/java/net/william278/velocitab/config/TabGroups.java index 0ea7a39..6a65239 100644 --- a/src/main/java/net/william278/velocitab/config/TabGroups.java +++ b/src/main/java/net/william278/velocitab/config/TabGroups.java @@ -48,10 +48,10 @@ public class TabGroups implements ConfigValidator { private static final Group DEFAULT_GROUP = new Group( "default", - List.of("&rainbow&Running Velocitab by William278"), - List.of("[There are currently %players_online%/%max_players_online% players online](gray)"), - "&7[%server%] &f%prefix%%username%", - new Nametag("&f%prefix%", "&f%suffix%"), + List.of("Running Velocitab by William278 & AlexDev_"), + List.of("There are currently %players_online%/%max_players_online% players online"), + "[%server%] %prefix%%username%", + new Nametag("%prefix%", "%suffix%"), Set.of("lobby", "survival", "creative", "minigames", "skyblock", "prison", "hub"), List.of("%role_weight%", "%username_lower%"), false, diff --git a/src/main/java/net/william278/velocitab/hook/MiniPlaceholdersHook.java b/src/main/java/net/william278/velocitab/hook/MiniPlaceholdersHook.java index 323af75..3b3c61e 100644 --- a/src/main/java/net/william278/velocitab/hook/MiniPlaceholdersHook.java +++ b/src/main/java/net/william278/velocitab/hook/MiniPlaceholdersHook.java @@ -27,15 +27,8 @@ import net.william278.velocitab.Velocitab; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; - public class MiniPlaceholdersHook extends Hook { - public final static Map REPLACE = Map.of( - "\"", "-q-", - "'", "-a-" - ); - private final VelocitabMiniExpansion expansion; public MiniPlaceholdersHook(@NotNull Velocitab plugin) { @@ -46,9 +39,6 @@ public class MiniPlaceholdersHook extends Hook { @NotNull public Component format(@NotNull String text, @NotNull Audience player, @Nullable Audience viewer) { - for (Map.Entry entry : REPLACE.entrySet()) { - text = text.replace(entry.getKey(), entry.getValue()); - } if (viewer == null) { return MiniMessage.miniMessage().deserialize(text, MiniPlaceholders.getAudienceGlobalPlaceholders(player)); } diff --git a/src/main/java/net/william278/velocitab/hook/VelocitabMiniExpansion.java b/src/main/java/net/william278/velocitab/hook/VelocitabMiniExpansion.java index 7e25748..8b767d6 100644 --- a/src/main/java/net/william278/velocitab/hook/VelocitabMiniExpansion.java +++ b/src/main/java/net/william278/velocitab/hook/VelocitabMiniExpansion.java @@ -26,12 +26,13 @@ import io.github.miniplaceholders.api.utils.TagsUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.william278.velocitab.Velocitab; import net.william278.velocitab.config.Placeholder; import net.william278.velocitab.hook.miniconditions.MiniConditionManager; import net.william278.velocitab.player.TabPlayer; +import org.jetbrains.annotations.NotNull; -import java.util.Map; import java.util.Optional; public class VelocitabMiniExpansion { @@ -96,11 +97,9 @@ public class VelocitabMiniExpansion { return TagsUtils.EMPTY_TAG; } - final String value = queue.pop().value(); + final String value = fixValue(popAll(queue)); String replaced = Placeholder.replaceInternal(value, plugin, targetPlayer); - for (final Map.Entry entry : Placeholder.SYMBOL_SUBSTITUTES.entrySet()) { - replaced = replaced.replace(entry.getValue(), entry.getKey()); - } + return Tag.selfClosingInserting(MiniMessage.miniMessage().deserialize(replaced, MiniPlaceholders.getAudienceGlobalPlaceholders(audience))); })); builder.relationalPlaceholder("vanish", ((a1, otherAudience, queue, ctx) -> { @@ -122,4 +121,23 @@ public class VelocitabMiniExpansion { expansion.unregister(); } + @NotNull + private String popAll(@NotNull ArgumentQueue queue) { + final StringBuilder builder = new StringBuilder(); + int i = 0; + while (queue.hasNext()) { + if (i > 0) { + builder.append(":"); + } + builder.append(queue.pop().value()); + i++; + } + return builder.toString(); + } + + @NotNull + private String fixValue(@NotNull String value) { + return value.replace("*LESS2*", "<").replace("*GREATER2*", ">"); + } + } diff --git a/src/main/java/net/william278/velocitab/hook/miniconditions/MiniConditionManager.java b/src/main/java/net/william278/velocitab/hook/miniconditions/MiniConditionManager.java index b55c011..dee4a22 100644 --- a/src/main/java/net/william278/velocitab/hook/miniconditions/MiniConditionManager.java +++ b/src/main/java/net/william278/velocitab/hook/miniconditions/MiniConditionManager.java @@ -26,7 +26,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.william278.velocitab.Velocitab; import net.william278.velocitab.config.Placeholder; -import net.william278.velocitab.hook.MiniPlaceholdersHook; import net.william278.velocitab.player.TabPlayer; import org.apache.commons.jexl3.JexlBuilder; import org.apache.commons.jexl3.JexlContext; @@ -43,6 +42,22 @@ import java.util.regex.Pattern; public class MiniConditionManager { + public final static Map REPLACE = Map.of( + "\"", "-q-", + "'", "-a-" + ); + + public final static Map REPLACE_2 = Map.of( + "*LESS3*", "<", + "*GREATER3*",">", + "*LESS2*", "<", + "*GREATER2*", ">" + ); + + private final static Map REPLACE_3 = Map.of( + "?dp?", ":" + ); + private final Velocitab plugin; private final JexlEngine jexlEngine; private final JexlContext jexlContext; @@ -82,6 +97,7 @@ public class MiniConditionManager { return Component.empty(); } + String condition = decodeCondition(parameters.get(0)); if (parameters.size() < 3) { plugin.getLogger().warn("Invalid condition: Missing true/false values for condition: {}", condition); @@ -93,8 +109,9 @@ public class MiniConditionManager { return Component.empty(); } + condition = Placeholder.replaceInternal(condition, plugin, tabPlayer.get()); - String falseValue = processFalseValue(parameters.get(2)); + final String falseValue = processFalseValue(parameters.get(2)); final String expression = buildExpression(condition); return evaluateAndFormatCondition(expression, target, audience, parameters.get(1), falseValue); } @@ -103,19 +120,25 @@ public class MiniConditionManager { private List collectParameters(@NotNull ArgumentQueue queue) { final List parameters = Lists.newArrayList(); while (queue.hasNext()) { - parameters.add(queue.pop().value()); + String param = queue.pop().value(); + for (Map.Entry entry : REPLACE_2.entrySet()) { + param = param.replace(entry.getKey(), entry.getValue()); + } + for (Map.Entry entry : REPLACE_3.entrySet()) { + param = param.replace(entry.getKey(), entry.getValue()); + } + parameters.add(param); } return parameters; } @NotNull private String decodeCondition(@NotNull String condition) { - condition = condition.replace("?lt;", "<").replace("?gt;", ">"); - for (Map.Entry entry : MiniPlaceholdersHook.REPLACE.entrySet()) { + for (Map.Entry entry : REPLACE.entrySet()) { condition = condition.replace(entry.getValue(), entry.getKey()); condition = condition.replace(entry.getKey() + entry.getKey(), entry.getKey()); } - for (Map.Entry entry : Placeholder.SYMBOL_SUBSTITUTES.entrySet()) { + for (Map.Entry entry : REPLACE_2.entrySet()) { condition = condition.replace(entry.getValue(), entry.getKey()); } return condition; diff --git a/src/main/java/net/william278/velocitab/player/TabPlayer.java b/src/main/java/net/william278/velocitab/player/TabPlayer.java index c7e8e69..5fb521b 100644 --- a/src/main/java/net/william278/velocitab/player/TabPlayer.java +++ b/src/main/java/net/william278/velocitab/player/TabPlayer.java @@ -161,16 +161,7 @@ public final class TabPlayer implements Comparable { displayName = displayName.replace(placeholder, value); } - displayName = displayName.replace("\n", ""); - final boolean isMiniMessage = plugin.getFormatter().equals(Formatter.MINIMESSAGE); - if (isMiniMessage) { - displayName = Formatter.LEGACY.serialize(MiniMessage.miniMessage().deserialize(displayName)); - } displayName = Placeholder.replaceInternal(displayName, plugin, this); - if (isMiniMessage) { - displayName = MiniMessage.miniMessage().serialize(Formatter.LEGACY.deserialize(displayName)) - .replace("\\<", "<"); - } return lastDisplayName = displayName; } diff --git a/src/main/java/net/william278/velocitab/tab/Nametag.java b/src/main/java/net/william278/velocitab/tab/Nametag.java index 2d80a38..cd29b25 100644 --- a/src/main/java/net/william278/velocitab/tab/Nametag.java +++ b/src/main/java/net/william278/velocitab/tab/Nametag.java @@ -21,6 +21,7 @@ package net.william278.velocitab.tab; import net.kyori.adventure.text.Component; import net.william278.velocitab.Velocitab; +import net.william278.velocitab.config.Placeholder; import net.william278.velocitab.player.TabPlayer; import org.jetbrains.annotations.NotNull; @@ -31,12 +32,14 @@ public record Nametag(@NotNull String prefix, @NotNull String suffix) { @NotNull public Component getPrefixComponent(@NotNull Velocitab plugin, @NotNull TabPlayer tabPlayer, @NotNull TabPlayer target) { - return plugin.getFormatter().format(prefix, tabPlayer, target, plugin); + final String formatted = Placeholder.replaceInternal(prefix, plugin, tabPlayer); + return plugin.getFormatter().format(formatted, tabPlayer, target, plugin); } @NotNull public Component getSuffixComponent(@NotNull Velocitab plugin, @NotNull TabPlayer tabPlayer, @NotNull TabPlayer target) { - return plugin.getFormatter().format(suffix, tabPlayer, target, plugin); + final String formatted = Placeholder.replaceInternal(suffix, plugin, tabPlayer); + return plugin.getFormatter().format(formatted, tabPlayer, target, plugin); } @Override diff --git a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java index d96fbaa..e61de01 100644 --- a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java +++ b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java @@ -286,6 +286,16 @@ public class PlayerTabList { removePlayer(target, null); } + /** + * Remove a player from the tab list + * @param uuid + */ + protected void removeTablistUUID(@NotNull UUID uuid) { + getPlayers().forEach((key, value) -> { + value.getPlayer().getTabList().getEntry(uuid).ifPresent(entry -> value.getPlayer().getTabList().removeEntry(uuid)); + }); + } + protected void removePlayer(@NotNull Player target, @Nullable RegisteredServer server) { final UUID uuid = target.getUniqueId(); plugin.getServer().getAllPlayers().forEach(player -> player.getTabList().removeEntry(uuid)); diff --git a/src/main/java/net/william278/velocitab/tab/TabListListener.java b/src/main/java/net/william278/velocitab/tab/TabListListener.java index 70a2345..083e263 100644 --- a/src/main/java/net/william278/velocitab/tab/TabListListener.java +++ b/src/main/java/net/william278/velocitab/tab/TabListListener.java @@ -168,8 +168,9 @@ public class TabListListener { if (player.getCurrentServer().isPresent()) { return; } - tabList.removePlayer(player); - }).delay(500, TimeUnit.MILLISECONDS).schedule(); + + tabList.removeTablistUUID(event.getPlayer().getUniqueId()); + }).delay(750, TimeUnit.MILLISECONDS).schedule(); } @Subscribe