refactor: Make MiniMessage the default formatter, fix bugs (#208)

* Fixed some problems
Changed default formatter to MINIMESAGE

* Removed debug message
This commit is contained in:
AlexDev_ 2024-08-11 14:31:56 +02:00 committed by GitHub
parent 77254f9228
commit fc39861f33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 229 additions and 166 deletions

View File

@ -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'
}

View File

@ -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'
- '<rainbow>Running Velocitab by William278 & AlexDev_</rainbow>'
- '<rainbow:10>Running Velocitab by William278 & AlexDev_</rainbow>'
- '<rainbow:20>Running Velocitab by William278 & AlexDev_</rainbow>'
```
</details>
@ -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'
- '<rainbow>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:2>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:18>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:20>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:22>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:24>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:26>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:28>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:30>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:32>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:34>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:36>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:38>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:40>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:42>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:44>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:46>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:48>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:50>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:52>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:54>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:56>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:58>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
- '<rainbow:60>Velocitab ⭐ A super-simple (sorted!) Velocity TAB menu plugin\n</rainbow>'
footers:
- |
\n&7For Velocity proxy servers:
&#1bd96a-#6cffa9&https://modrinth.com/plugin/velocitab
&#1bd96a-#6cffa9&https://william278.net/project/veloictab'
format: '&#999-#fff&[%server%] &f%username%'
\n<gray>For Velocity proxy servers:</gray>
<gradient:#1bd96a:#6cffa9>https://modrinth.com/plugin/velocitab</gradient>
<gradient:#1bd96a:#6cffa9>https://william278.net/project/veloictab</gradient>'
format: '<gradient:#999:#fff>[%server%] &f%username%</gradient>'
header_footer_update_rate: 200
```
In config.yml
```yaml
formatter: MINEDOWN
formatter: MINIMESSAGE
```
</details>

View File

@ -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: '&#00fb9a&About Velocitab'
- label: '<#00fb9a>About Velocitab</#00fb9a>'
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:
- <rainbow:!2>Running Velocitab by William278 & AlexDev_</rainbow>
footers:
- <gray>There are currently %players_online%/%max_players_online% players online</gray>
format: <gray>[%server%] %prefix%%username%</gray>
nametag:
prefix: <white>%prefix%</white>
suffix: <white>%suffix%</white>
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
```
</details>

View File

@ -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!

View File

@ -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)

View File

@ -17,9 +17,9 @@ rate to use for the group.
```yaml
headers:
- '&rainbow&Running Velocitab by William278'
- '<rainbow>Running Velocitab by William278 & AlexDev_</rainbow>'
footers:
- '[There are currently %players_online%/%max_players_online% players online](gray)'
- '<gray>There are currently %players_online%/%max_players_online% players online</gray>'
```
</details>
@ -35,7 +35,7 @@ information.
<summary>Example of format</summary>
```yaml
format: '&7[%server%] &f%prefix%%username%'
format: '<gray>[%server%] %prefix%%username%</gray>'
```
</details>
@ -51,8 +51,8 @@ Player formats may only utilize one line.
```yaml
nametag:
prefix: '&f%prefix%'
suffix: '&f%suffix%'
prefix: '<white>%prefix%</white>'
suffix: '<white>%suffix%</white>'
```
</details>
@ -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!'
- '<rainbow:!2>Running Velocitab by William278 & AlexDev_ on Lobbies!</rainbow>'
footers:
- '[There are currently %players_online%/%max_players_online% players online](gray)'
format: '&7[%server%] &f%prefix%%username%'
- '<gray>There are currently %players_online%/%max_players_online% players online</gray>'
format: '<gray>[%server%] %prefix%%username%</gray>'
servers:
- lobby
- hub
@ -165,10 +165,10 @@ groups:
placeholder_update_rate: 1000
- name: creative
headers:
- '&rainbow&Running Velocitab by William278 on Creative!'
- '<rainbow:!2>Running Velocitab by William278 & AlexDev_ on Creative!</rainbow>'
footers:
- '[There are currently %players_online%/%max_players_online% players online](gray)'
format: '&7[%server%] &f%prefix%%username%'
- '<gray>There are currently %players_online%/%max_players_online% players online</gray>'
format: '<gray>[%server%] %prefix%%username%</gray>'
servers:
- creative
sorting_placeholders:
@ -178,10 +178,10 @@ groups:
placeholder_update_rate: 1000
- name: survival
headers:
- '&rainbow&Running Velocitab by William278 on Survival!'
- '<rainbow:!2>Running Velocitab by William278 & AlexDev_ on Survival!</rainbow>'
footers:
- '[There are currently %players_online%/%max_players_online% players online](gray)'
format: '&7[%server%] &f%prefix%%username%'
- '<gray>There are currently %players_online%/%max_players_online% players online</gray>'
format: '<gray>[%server%] %prefix%%username%</gray>'
servers:
- survival
sorting_placeholders:

View File

@ -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);

View File

@ -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",

View File

@ -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("<velocitab_.*?>");
private final static Pattern TEST = Pattern.compile("<.*?>");
private final static Pattern CONDITION_REPLACER = Pattern.compile("<velocitab_rel_condition:[^:]*:");
private final static Pattern PLACEHOLDER_PATTERN = Pattern.compile("%.*?%");
private final static Pattern CONDITIONAL_PATTERN = Pattern.compile("<velocitab_rel_condition:[^:]*:[^:]*:[^:]*>");
private final static String DELIMITER = ":::";
private final static String REL_SUBSTITUTE = "-REL-";
public final static Map<String, String> SYMBOL_SUBSTITUTES = Map.of(
"<", "-COND-1",
">", "-COND-2"
private final static Map<String, String> SYMBOL_SUBSTITUTES = Map.of(
"<", "*LESS*",
">", "*GREATER*"
);
private final static Map<String, String> 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<Boolean, String> processRelationalPlaceholders(@NotNull String format, @NotNull Velocitab plugin) {
boolean foundRelational = false;
if (format.contains("<vel") && plugin.getFormatter().equals(Formatter.MINIMESSAGE)) {
final Matcher velocitabRelationalMatcher = VELOCITAB_PATTERN.matcher(format);
while (velocitabRelationalMatcher.find()) {
if (velocitabRelationalMatcher.group().contains("rel_condition")) {
if (plugin.getFormatter().equals(Formatter.MINIMESSAGE) && format.contains("<vel")) {
final Matcher conditionReplacer = CONDITION_REPLACER.matcher(format);
while (conditionReplacer.find()) {
final String search = conditionReplacer.group().split(":")[1];
String condition = search;
for (Map.Entry<String, String> entry : MiniConditionManager.REPLACE.entrySet()) {
condition = condition.replace(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, String> 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("<velocitab_rel")) {
final Matcher second = TEST.matcher(testMatcher.group().substring(1));
while (second.find()) {
String s = second.group();
for (Map.Entry<String, String> 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<String, String> 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<String, String> entry : SYMBOL_SUBSTITUTES_2.entrySet()) {
fixedString = fixedString.replace(entry.getKey(), entry.getValue());
}
format = format.replace(relationalPlaceholder, fixedString);
}
format = processConditionalPlaceholders(format);
for (Map.Entry<String, String> 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<String, String> entry : SYMBOL_SUBSTITUTES.entrySet()) {
fixedString = fixedString.replace(entry.getKey(), entry.getValue());
}
return fixedString;
}
public static CompletableFuture<String> replace(@NotNull String format, @NotNull Velocitab plugin,
@NotNull TabPlayer player) {

View File

@ -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;

View File

@ -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<ServerUrl> serverLinks = List.of(
new ServerUrl(
"&#00fb9a&About Velocitab",
"<#00fb9a>About Velocitab</#00fb9a>",
"https://william278.net/project/velocitab"
)
);

View File

@ -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("<rainbow:!2>Running Velocitab by William278 & AlexDev_</rainbow>"),
List.of("<gray>There are currently %players_online%/%max_players_online% players online</gray>"),
"<gray>[%server%] %prefix%%username%</gray>",
new Nametag("<white>%prefix%</white>", "<white>%suffix%</white>"),
Set.of("lobby", "survival", "creative", "minigames", "skyblock", "prison", "hub"),
List.of("%role_weight%", "%username_lower%"),
false,

View File

@ -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<String, String> 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<String, String> entry : REPLACE.entrySet()) {
text = text.replace(entry.getKey(), entry.getValue());
}
if (viewer == null) {
return MiniMessage.miniMessage().deserialize(text, MiniPlaceholders.getAudienceGlobalPlaceholders(player));
}

View File

@ -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<String, String> 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*", ">");
}
}

View File

@ -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<String, String> REPLACE = Map.of(
"\"", "-q-",
"'", "-a-"
);
public final static Map<String, String> REPLACE_2 = Map.of(
"*LESS3*", "<",
"*GREATER3*",">",
"*LESS2*", "<",
"*GREATER2*", ">"
);
private final static Map<String, String> 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<String> collectParameters(@NotNull ArgumentQueue queue) {
final List<String> parameters = Lists.newArrayList();
while (queue.hasNext()) {
parameters.add(queue.pop().value());
String param = queue.pop().value();
for (Map.Entry<String, String> entry : REPLACE_2.entrySet()) {
param = param.replace(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, String> 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<String, String> entry : MiniPlaceholdersHook.REPLACE.entrySet()) {
for (Map.Entry<String, String> entry : REPLACE.entrySet()) {
condition = condition.replace(entry.getValue(), entry.getKey());
condition = condition.replace(entry.getKey() + entry.getKey(), entry.getKey());
}
for (Map.Entry<String, String> entry : Placeholder.SYMBOL_SUBSTITUTES.entrySet()) {
for (Map.Entry<String, String> entry : REPLACE_2.entrySet()) {
condition = condition.replace(entry.getValue(), entry.getKey());
}
return condition;

View File

@ -161,16 +161,7 @@ public final class TabPlayer implements Comparable<TabPlayer> {
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;
}

View File

@ -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

View File

@ -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));

View File

@ -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