forked from Upstream/Velocitab
Added regex system and fixed ghost players bug (#176)
* Added regex system for TabGroup's servers. Fixed ghost player after kick/disconnect. * Fixed config docs with missing entries * Bumped version
This commit is contained in:
parent
c0abf481c1
commit
4e2749ac9e
@ -17,6 +17,8 @@ The config file is located in `/plugins/velocitab/config.yml` and the tab groups
|
||||
check_for_updates: true
|
||||
# Whether to remove nametag from players' heads if the nametag associated with their server group is empty.
|
||||
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
|
||||
# All servers which are not in other groups will be put in the fallback group.
|
||||
@ -33,16 +35,21 @@ server_display_names:
|
||||
# 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)
|
||||
papi_cache_time: 200
|
||||
papi_cache_time: 30000
|
||||
# If you are using MINIMESSAGE formatting, enable this to support MiniPlaceholders in formatting.
|
||||
enable_mini_placeholders_hook: true
|
||||
# Whether to send scoreboard teams packets. Required for player list sorting and nametag formatting.
|
||||
# Turn this off if you're using scoreboard teams on backend servers.
|
||||
send_scoreboard_packets: true
|
||||
# If built-in placeholders return a blank string, fallback to Placeholder API equivalents.
|
||||
# For example, if %prefix% returns a blank string, use %luckperms_prefix%. Requires PAPIProxyBridge.
|
||||
fallback_to_papi_if_placeholder_blank: false
|
||||
# Whether to sort players in the TAB list.
|
||||
sort_players: true
|
||||
# Remove gamemode spectator effect for other players in the TAB list.
|
||||
remove_spectator_effect: false
|
||||
# Whether to enable the Plugin Message API (allows backend plugins to perform certain operations)
|
||||
enable_plugin_message_api: true
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -3,7 +3,7 @@ javaVersion=17
|
||||
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
||||
org.gradle.daemon=true
|
||||
|
||||
plugin_version=1.6.3
|
||||
plugin_version=1.6.4
|
||||
plugin_archive=velocitab
|
||||
plugin_description=A beautiful and versatile TAB list plugin for Velocity proxies
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package net.william278.velocitab.config;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import net.william278.velocitab.Velocitab;
|
||||
@ -27,9 +28,12 @@ import net.william278.velocitab.tab.Nametag;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public record Group(
|
||||
@ -38,8 +42,8 @@ public record Group(
|
||||
List<String> footers,
|
||||
String format,
|
||||
Nametag nametag,
|
||||
List<String> servers,
|
||||
List<String> sortingPlaceholders,
|
||||
Set<String> servers,
|
||||
Set<String> sortingPlaceholders,
|
||||
boolean collisions,
|
||||
int headerFooterUpdateRate,
|
||||
int placeholderUpdateRate
|
||||
@ -58,15 +62,35 @@ public record Group(
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<RegisteredServer> registeredServers(Velocitab plugin) {
|
||||
public Set<RegisteredServer> registeredServers(@NotNull Velocitab plugin) {
|
||||
if (isDefault() && plugin.getSettings().isFallbackEnabled()) {
|
||||
return new ArrayList<>(plugin.getServer().getAllServers());
|
||||
return Sets.newHashSet(plugin.getServer().getAllServers());
|
||||
}
|
||||
return servers.stream()
|
||||
.map(plugin.getServer()::getServer)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.toList();
|
||||
return getRegexServers(plugin);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<RegisteredServer> getRegexServers(@NotNull Velocitab plugin) {
|
||||
final Set<RegisteredServer> totalServers = Sets.newHashSet();
|
||||
for (String server : servers) {
|
||||
if (!server.contains("*") && !server.contains(".")) {
|
||||
plugin.getServer().getServer(server).ifPresent(totalServers::add);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
final Matcher matcher = Pattern.compile(server
|
||||
.replace(".", "\\.")
|
||||
.replace("*", ".*"))
|
||||
.matcher("");
|
||||
plugin.getServer().getAllServers().stream()
|
||||
.filter(registeredServer -> matcher.reset(registeredServer.getServerInfo().getName()).matches())
|
||||
.forEach(totalServers::add);
|
||||
} catch (PatternSyntaxException ignored) {
|
||||
plugin.getServer().getServer(server).ifPresent(totalServers::add);
|
||||
}
|
||||
}
|
||||
return totalServers;
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
@ -74,8 +98,8 @@ public record Group(
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Player> getPlayers(Velocitab plugin) {
|
||||
List<Player> players = new ArrayList<>();
|
||||
public Set<Player> getPlayers(@NotNull Velocitab plugin) {
|
||||
Set<Player> players = Sets.newHashSet();
|
||||
for (RegisteredServer server : registeredServers(plugin)) {
|
||||
players.addAll(server.getPlayersConnected());
|
||||
}
|
||||
@ -83,12 +107,12 @@ public record Group(
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<TabPlayer> getTabPlayers(Velocitab plugin) {
|
||||
public Set<TabPlayer> getTabPlayers(@NotNull Velocitab plugin) {
|
||||
return plugin.getTabList().getPlayers()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(tabPlayer -> tabPlayer.getGroup().equals(this))
|
||||
.toList();
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,6 +50,9 @@ public class Settings implements ConfigValidator {
|
||||
@Comment("Whether to remove nametag from players' heads if the nametag associated with their server group is empty.")
|
||||
private boolean removeNametags = false;
|
||||
|
||||
@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;
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package net.william278.velocitab.config;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import de.exlll.configlib.Configuration;
|
||||
@ -29,10 +30,7 @@ import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.tab.Nametag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
@Getter
|
||||
@ -54,8 +52,8 @@ public class TabGroups implements ConfigValidator {
|
||||
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("lobby", "survival", "creative", "minigames", "skyblock", "prison", "hub"),
|
||||
List.of("%role_weight%", "%username_lower%"),
|
||||
Set.of("lobby", "survival", "creative", "minigames", "skyblock", "prison", "hub"),
|
||||
Set.of("%role_weight%", "%username_lower%"),
|
||||
false,
|
||||
1000,
|
||||
1000
|
||||
@ -113,7 +111,7 @@ public class TabGroups implements ConfigValidator {
|
||||
|
||||
@NotNull
|
||||
private Multimap<Group, String> getMissingKeys() {
|
||||
final Multimap<Group, String> missingKeys = Multimaps.newSetMultimap(new HashMap<>(), HashSet::new);
|
||||
final Multimap<Group, String> missingKeys = Multimaps.newSetMultimap(Maps.newHashMap(), HashSet::new);
|
||||
|
||||
for (Group group : groups) {
|
||||
if (group.format() == null) {
|
||||
|
@ -113,7 +113,7 @@ public class ScoreboardManager {
|
||||
if (teamName == null) {
|
||||
return;
|
||||
}
|
||||
final List<RegisteredServer> siblings = tabPlayer.getGroup().registeredServers(plugin);
|
||||
final Set<RegisteredServer> siblings = tabPlayer.getGroup().registeredServers(plugin);
|
||||
|
||||
final Optional<Nametag> cachedTag = Optional.ofNullable(nametags.getOrDefault(teamName, null));
|
||||
cachedTag.ifPresent(nametag -> {
|
||||
@ -175,7 +175,7 @@ public class ScoreboardManager {
|
||||
}
|
||||
|
||||
final Player player = tabPlayer.getPlayer();
|
||||
final List<RegisteredServer> siblings = tabPlayer.getGroup().registeredServers(plugin);
|
||||
final Set<RegisteredServer> siblings = tabPlayer.getGroup().registeredServers(plugin);
|
||||
final List<Player> players = siblings.stream()
|
||||
.map(RegisteredServer::getPlayersConnected)
|
||||
.flatMap(Collection::stream)
|
||||
@ -253,7 +253,7 @@ public class ScoreboardManager {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<RegisteredServer> siblings = tabPlayer.getGroup().registeredServers(plugin);
|
||||
final Set<RegisteredServer> siblings = tabPlayer.getGroup().registeredServers(plugin);
|
||||
siblings.forEach(server -> server.getPlayersConnected().forEach(connected -> {
|
||||
try {
|
||||
final boolean canSee = plugin.getVanishManager().canSee(connected.getUsername(), player.getUsername());
|
||||
|
@ -41,6 +41,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
@ToString
|
||||
public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
|
||||
private final Velocitab plugin;
|
||||
private final Player player;
|
||||
@Setter
|
||||
private Role role;
|
||||
@ -65,7 +66,9 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
@Setter
|
||||
private boolean loaded;
|
||||
|
||||
public TabPlayer(@NotNull Player player, @NotNull Role role, @NotNull Group group) {
|
||||
public TabPlayer(@NotNull Velocitab plugin, @NotNull Player player,
|
||||
@NotNull Role role, @NotNull Group group) {
|
||||
this.plugin = plugin;
|
||||
this.player = player;
|
||||
this.role = role;
|
||||
this.group = group;
|
||||
@ -134,11 +137,22 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> sendHeaderAndFooter(@NotNull PlayerTabList tabList) {
|
||||
return tabList.getHeader(this).thenCompose(header -> tabList.getFooter(this)
|
||||
.thenAccept(footer -> {
|
||||
return tabList.getHeader(this).thenCompose(header -> tabList.getFooter(this).thenAccept(footer -> {
|
||||
final boolean disabled = plugin.getSettings().isDisableHeaderFooterIfEmpty();
|
||||
if (disabled) {
|
||||
if (!Component.empty().equals(header)) {
|
||||
lastHeader = header;
|
||||
player.sendPlayerListHeader(header);
|
||||
}
|
||||
if (!Component.empty().equals(footer)) {
|
||||
lastFooter = footer;
|
||||
player.sendPlayerListFooter(footer);
|
||||
}
|
||||
} else {
|
||||
lastHeader = header;
|
||||
lastFooter = footer;
|
||||
player.sendPlayerListHeaderAndFooter(header, footer);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ public class PlayerTabList {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<RegisteredServer> serversInGroup = Lists.newArrayList(tabPlayer.getGroup().registeredServers(plugin));
|
||||
final Set<RegisteredServer> serversInGroup = tabPlayer.getGroup().registeredServers(plugin);
|
||||
if (serversInGroup.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -283,7 +283,7 @@ public class PlayerTabList {
|
||||
|
||||
@NotNull
|
||||
public TabPlayer createTabPlayer(@NotNull Player player, @NotNull Group group) {
|
||||
return new TabPlayer(player,
|
||||
return new TabPlayer(plugin, player,
|
||||
plugin.getLuckPermsHook().map(hook -> hook.getPlayerRole(player)).orElse(Role.DEFAULT_ROLE),
|
||||
group
|
||||
);
|
||||
@ -379,7 +379,7 @@ public class PlayerTabList {
|
||||
* @param incrementIndexes Whether to increment the header and footer indexes.
|
||||
*/
|
||||
private void updateGroupPlayers(@NotNull Group group, boolean all, boolean incrementIndexes) {
|
||||
List<TabPlayer> groupPlayers = group.getTabPlayers(plugin);
|
||||
Set<TabPlayer> groupPlayers = group.getTabPlayers(plugin);
|
||||
if (groupPlayers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ public class TabListListener {
|
||||
@Subscribe(order = PostOrder.LAST)
|
||||
public void onPlayerQuit(@NotNull DisconnectEvent event) {
|
||||
if (event.getLoginStatus() != DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN) {
|
||||
checkDelayedDisconnect(event);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -124,6 +125,21 @@ public class TabListListener {
|
||||
tabList.removePlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
private void checkDelayedDisconnect(@NotNull DisconnectEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
plugin.getServer().getScheduler().buildTask(plugin, () -> {
|
||||
final Optional<Player> actualPlayer = plugin.getServer().getPlayer(player.getUniqueId());
|
||||
if (actualPlayer.isPresent() && !actualPlayer.get().equals(player)) {
|
||||
return;
|
||||
}
|
||||
if (player.getCurrentServer().isPresent()) {
|
||||
return;
|
||||
}
|
||||
tabList.removePlayer(player);
|
||||
plugin.log("Player " + player.getUsername() + " was not removed from the tab list, removing now.");
|
||||
}).delay(500, TimeUnit.MILLISECONDS).schedule();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void proxyReload(@NotNull ProxyReloadEvent event) {
|
||||
plugin.loadConfigs();
|
||||
|
@ -24,8 +24,8 @@ import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -79,7 +79,7 @@ public class VanishTabList {
|
||||
*/
|
||||
public void recalculateVanishForPlayer(@NotNull TabPlayer tabPlayer) {
|
||||
final Player player = tabPlayer.getPlayer();
|
||||
final List<String> serversInGroup = tabPlayer.getGroup().servers();
|
||||
final Set<String> serversInGroup = tabPlayer.getGroup().servers();
|
||||
|
||||
plugin.getServer().getAllPlayers().forEach(p -> {
|
||||
if (p.equals(player)) {
|
||||
|
Loading…
Reference in New Issue
Block a user