Skip to content

Commit

Permalink
1.7.3 - Placeholders Replacements & 1.21.4 (#236)
Browse files Browse the repository at this point in the history
* Added PlaceholderReplacements

* Removed server display names

* Fixed disconnect problem

* Added support for 1.21.4
  • Loading branch information
alexdev03 authored Dec 3, 2024
1 parent 2ba2080 commit 24c29e6
Show file tree
Hide file tree
Showing 17 changed files with 259 additions and 73 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ tasks {
velocityVersion("${velocity_api_version}-SNAPSHOT")

downloadPlugins {
modrinth ("papiproxybridge", papi)
github ("WiIIiam278", "PAPIProxyBridge", "1.7.1", "PAPIProxyBridge-Velocity-1.7.1.jar")
modrinth ("miniplaceholders", "2.2.4")
}
}
Expand Down
15 changes: 11 additions & 4 deletions docs/Config-File.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ fallback_enabled: true
fallback_group: default
# Whether to show all players from all groups in the TAB list.
show_all_players_from_all_groups: false
# Define custom names to be shown in the TAB list for specific server names.
# If no custom display name is provided for a server, its original name will be used.
server_display_names:
very-long-server-name: VLSN
# Whether to enable the PAPIProxyBridge hook for PAPI support
enable_papi_hook: true
# How long in seconds to cache PAPI placeholders for, in milliseconds. (0 to disable)
Expand Down Expand Up @@ -101,6 +97,14 @@ groups:
sorting_placeholders:
- '%role_weight%'
- '%username_lower%'
placeholder_replaments:
'%current_date_weekday_en-US%':
- placeholder: Monday
replacement: <red>Monday</red>
- placeholder: Tuesday
replacement: <gold>Tuesday</gold>
- placeholder: Else
replacement: <green>Other day</green>
collisions: false
header_footer_update_rate: 1000
placeholder_update_rate: 1000
Expand All @@ -127,3 +131,6 @@ You can use various placeholders that will be replaced with values (for example,

### Server Links
For Minecraft 1.21+ clients, Velocitab supports specifying a list of URLs that will be sent to display in the player pause menu. See [[Server Links]] for more information.

### Placeholder Replaments
Velocitab supports replacing values of placeholders with other values. See [[Placeholders Replaments]] for more information.
88 changes: 88 additions & 0 deletions docs/Placeholders-Replaments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@

Velocitab supports placeholder replacements, which allow you to replace a placeholder with a different value. This is useful for things like changing the text of a date placeholder to a localized version, changing the text of a biome placeholder to a color or you can use a vanish placeholder to show a player's vanish status if the placeholder returns just a boolean (true/false).


## Configuring

Placeholder replacements are configured in the `placeholder_replaments` section of the every Tab Group.
You can specify a list of replacements for a placeholder, and the replacements will be applied in the order they are listed.

The replacements are specified as a list of objects with two properties: `placeholder` and `replacement`.
`placeholder` is the placeholder to replace, and `replacement` is the replacement text.

### Example section
```yaml
placeholder_replaments:
'%current_date_weekday_en-US%':
- placeholder: Monday
replacement: <red>Monday</red>
- placeholder: Tuesday
replacement: <gold>Tuesday</gold>
- placeholder: Else
replacement: <green>Other day</green>
'%player_world_type%':
- placeholder: Overworld
replacement: '<aqua>Overworld</aqua>'
- placeholder: Nether
replacement: '<red>Nether</red>'
- placeholder: End
replacement: '<yellow>End</yellow>'
'%player_biome%':
- placeholder: PLAINS
replacement: <red>Plains</red>
- placeholder: DESERT
replacement: <yellow>Desert</yellow>
- placeholder: RIVER
replacement: <aqua>River</aqua>
```
## Specified cases
### Vanish status
If you want to show a player's vanish status, for example, you can use the `%advancedvanish_is_vanished%` placeholder.
This placeholder returns a boolean value, so you can use it to show a player's vanish status.

For example, if you wanted to show a player's vanish status as a color, you could use the following replacements:
```yaml
placeholder_replaments:
'%advancedvanish_is_vanished%':
- placeholder: Yes
replacement: <red>Vanished</red>
- placeholder: No
replacement: <green>Not vanished</green>
```

### Else clause
If you don't want to specify every possible value for a placeholder, you can use the `ELSE` placeholder.
This placeholder will be replaced with the replacement text of the first replacement that doesn't have a placeholder.

For example, if you wanted to show the current date as a color, you could use the following replacements:
```yaml
placeholder_replaments:
'%current_date_weekday_en-US%':
- placeholder: Monday
replacement: <red>Monday</red>
- placeholder: Tuesday
replacement: <gold>Tuesday</gold>
- placeholder: ELSE
replacement: <green>Other day</green>
```

### Placeholder not present in a server
If you have a group with multiple servers, and you have a placeholder that is not present in one of the servers, you can use the `%<placeholder>%` as a placeholder it will handle the case where the placeholder is not present in the server.

```yaml
placeholder_replaments:
'%huskhomes_homes_count%':
- placeholder: '%huskhomes_homes_count%'
replacement: <red>No homes in this server</red>
```

If you want you can also set the replacement as an empty string, which will be replaced with the empty string.

```yaml
placeholder_replaments:
'%huskhomes_homes_count%':
- placeholder: '%huskhomes_homes_count%'
replacement: ''
```
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ javaVersion=17
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.daemon=true

plugin_version=1.7.2
plugin_version=1.7.3
plugin_archive=velocitab
plugin_description=A beautiful and versatile TAB list plugin for Velocity proxies

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/william278/velocitab/config/Group.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.slf4j.event.Level;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -46,6 +47,7 @@ public record Group(
Nametag nametag,
Set<String> servers,
List<String> sortingPlaceholders,
Map<String, List<PlaceholderReplacement>> placeholderReplaments,
boolean collisions,
int headerFooterUpdateRate,
int placeholderUpdateRate,
Expand Down
125 changes: 91 additions & 34 deletions src/main/java/net/william278/velocitab/config/Placeholder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package net.william278.velocitab.config;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import it.unimi.dsi.fastutil.Pair;
Expand All @@ -36,8 +38,7 @@
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -95,7 +96,7 @@ public enum Placeholder {
}),
USERNAME((plugin, player) -> player.getCustomName().orElse(player.getPlayer().getUsername())),
USERNAME_LOWER((plugin, player) -> player.getCustomName().orElse(player.getPlayer().getUsername()).toLowerCase()),
SERVER((plugin, player) -> player.getServerDisplayName(plugin)),
SERVER((plugin, player) -> player.getServerName()),
PING((plugin, player) -> Long.toString(player.getPlayer().getPing())),
PREFIX((plugin, player) -> player.getRole().getPrefix()
.orElse(getPlaceholderFallback(plugin, "%luckperms_prefix%"))),
Expand Down Expand Up @@ -126,6 +127,9 @@ public enum Placeholder {
"*LESS*", "*LESS2*",
"*GREATER*", "*GREATER2*"
);
private final static String VEL_PLACEHOLDER = "<vel";
private final static String VELOCITAB_PLACEHOLDER = "<velocitab_rel";
private final static String ELSE_PLACEHOLDER = "ELSE";

/**
* Function to replace placeholders with a real value
Expand Down Expand Up @@ -162,17 +166,13 @@ private static String getPlaceholderFallback(@NotNull Velocitab plugin, @NotNull
}

@NotNull
public static String replaceInternal(@NotNull String format, @NotNull Velocitab plugin, @Nullable TabPlayer player) {
final Pair<Boolean, String> result = processRelationalPlaceholders(format, plugin);
format = result.right();
format = replacePlaceholders(format, plugin, player);

return format;
public static Pair<String, Map<String, String>> replaceInternal(@NotNull String format, @NotNull Velocitab plugin, @Nullable TabPlayer player) {
format = processRelationalPlaceholders(format, plugin);
return replacePlaceholders(format, plugin, player);
}

private static Pair<Boolean, String> processRelationalPlaceholders(@NotNull String format, @NotNull Velocitab plugin) {
boolean foundRelational = false;
if (plugin.getFormatter().equals(Formatter.MINIMESSAGE) && format.contains("<vel")) {
private static String processRelationalPlaceholders(@NotNull String format, @NotNull Velocitab plugin) {
if (plugin.getFormatter().equals(Formatter.MINIMESSAGE) && format.contains(VEL_PLACEHOLDER)) {
final Matcher conditionReplacer = CONDITION_REPLACER.matcher(format);
while (conditionReplacer.find()) {

Expand All @@ -189,7 +189,7 @@ private static Pair<Boolean, String> processRelationalPlaceholders(@NotNull Stri

final Matcher testMatcher = TEST.matcher(format);
while (testMatcher.find()) {
if (testMatcher.group().startsWith("<velocitab_rel")) {
if (testMatcher.group().startsWith(VELOCITAB_PLACEHOLDER)) {
final Matcher second = TEST.matcher(testMatcher.group().substring(1));
while (second.find()) {
String s = second.group();
Expand All @@ -209,7 +209,6 @@ private static Pair<Boolean, String> processRelationalPlaceholders(@NotNull Stri

final Matcher velocitabRelationalMatcher = VELOCITAB_PATTERN.matcher(format);
while (velocitabRelationalMatcher.find()) {
foundRelational = true;
final String relationalPlaceholder = velocitabRelationalMatcher.group().substring(1, velocitabRelationalMatcher.group().length() - 1);
String fixedString = relationalPlaceholder;
for (Map.Entry<String, String> entry : SYMBOL_SUBSTITUTES_2.entrySet()) {
Expand All @@ -223,25 +222,58 @@ private static Pair<Boolean, String> processRelationalPlaceholders(@NotNull Stri
}

}
return Pair.of(foundRelational, format);
return format;
}

@NotNull
private static String replacePlaceholders(@NotNull String format, @NotNull Velocitab plugin, @Nullable TabPlayer player) {
private static Pair<String, Map<String, String>> replacePlaceholders(@NotNull String format, @NotNull Velocitab plugin,
@Nullable TabPlayer player) {
final Map<String, String> replacedPlaceholders = Maps.newHashMap();
for (Placeholder placeholder : values()) {
Matcher matcher = placeholder.pattern.matcher(format);
final Matcher matcher = placeholder.pattern.matcher(format);
if (placeholder.parameterised) {
format = matcher.replaceAll(matchResult ->
Matcher.quoteReplacement(
placeholder.replacer.apply(StringUtils.chop(matchResult.group().replace("%" + placeholder.name().toLowerCase(), "")
.replaceFirst("_", ""))
, plugin, player)
));
format = matcher.replaceAll(matchResult -> {
final String replacement = placeholder.replacer.apply(StringUtils.chop(matchResult.group().replace("%" + placeholder.name().toLowerCase(), "")
.replaceFirst("_", "")), plugin, player);
replacedPlaceholders.put(matchResult.group(), replacement);
return Matcher.quoteReplacement(replacement);
});
} else {
format = matcher.replaceAll(matchResult -> Matcher.quoteReplacement(placeholder.replacer.apply(null, plugin, player)));
format = matcher.replaceAll(matchResult -> {
final String replacement = placeholder.replacer.apply(null, plugin, player);
replacedPlaceholders.put(matchResult.group(), replacement);
return Matcher.quoteReplacement(replacement);
});
}
}
return format;
return Pair.of(format, replacedPlaceholders);
}

@NotNull
private static String applyPlaceholderReplacements(@NotNull String text, @NotNull TabPlayer player,
@NotNull Map<String, String> parsed) {
for (final Map.Entry<String, List<PlaceholderReplacement>> entry : player.getGroup().placeholderReplaments().entrySet()) {
if (!parsed.containsKey(entry.getKey())) {
continue;
}

final String replaced = parsed.get(entry.getKey());
final Optional<PlaceholderReplacement> replacement = entry.getValue().stream()
.filter(r -> r.placeholder().equalsIgnoreCase(replaced))
.findFirst();

if (replacement.isPresent()) {
text = text.replace(entry.getKey(), replacement.get().replacement());
} else {
final Optional<PlaceholderReplacement> elseReplacement = entry.getValue().stream()
.filter(r -> r.placeholder().equalsIgnoreCase(ELSE_PLACEHOLDER))
.findFirst();
if (elseReplacement.isPresent()) {
text = text.replace(entry.getKey(), elseReplacement.get().replacement());
}
}
}
return applyPlaceholders(text, parsed);
}

public static CompletableFuture<String> replace(@NotNull String format, @NotNull Velocitab plugin,
Expand All @@ -251,22 +283,47 @@ public static CompletableFuture<String> replace(@NotNull String format, @NotNull
return CompletableFuture.completedFuture("");
}

final String replaced = replaceInternal(format, plugin, player);

if (!PLACEHOLDER_PATTERN.matcher(replaced).find()) {
return CompletableFuture.completedFuture(replaced);
final Pair<String, Map<String, String>> replaced = replaceInternal(format, plugin, player);
if (!PLACEHOLDER_PATTERN.matcher(replaced.first()).find()) {
return CompletableFuture.completedFuture(replaced.first());
}

final List<String> placeholders = extractPlaceholders(replaced.first());
return plugin.getPAPIProxyBridgeHook()
.map(hook -> hook.formatPlaceholders(replaced, player.getPlayer())
.map(hook -> hook.parsePlaceholders(placeholders, player.getPlayer())
.exceptionally(e -> {
plugin.log(Level.ERROR, "An error occurred whilst parsing placeholders: " + e.getMessage());
return replaced;
return Map.of();
})
)
.orElse(CompletableFuture.completedFuture(replaced)).exceptionally(e -> {
.orElse(CompletableFuture.completedFuture(Maps.newHashMap())).exceptionally(e -> {
plugin.log(Level.ERROR, "An error occurred whilst parsing placeholders: " + e.getMessage());
return replaced;
});
return Map.of();
})
.thenApply(m -> applyPlaceholderReplacements(format, player, mergeMaps(m, replaced.second())));
}

@NotNull
private static String applyPlaceholders(@NotNull String text, @NotNull Map<String, String> replacements) {
for (Map.Entry<String, String> entry : replacements.entrySet()) {
text = text.replace(entry.getKey(), entry.getValue());
}
return text;
}

@NotNull
private static Map<String, String> mergeMaps(@NotNull Map<String, String> map1, @NotNull Map<String, String> map2) {
map1.putAll(map2);
return map1;
}

@NotNull
private static List<String> extractPlaceholders(@NotNull String text) {
final List<String> placeholders = Lists.newArrayList();
final Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);
while (matcher.find()) {
placeholders.add(matcher.group());
}
return placeholders;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This file is part of Velocitab, licensed under the Apache License 2.0.
*
* Copyright (c) William278 <[email protected]>
* Copyright (c) contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.william278.velocitab.config;

import org.jetbrains.annotations.NotNull;

public record PlaceholderReplacement(@NotNull String placeholder, @NotNull String replacement) {
}
Loading

0 comments on commit 24c29e6

Please sign in to comment.