forked from Upstream/Velocitab
Added support for nametags and fixed a few problems (#84)
* Added regex check for placeholders to avoid useless requests. Added support for custom nametags. Due to minecraft limit only legacy chatcolor are supported. Team names now are unique, so 1 team can have max 1 player. Fixed problem with luckperms event bus while reloading the plugin. * Update src/main/java/net/william278/velocitab/config/Placeholder.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/hook/LuckPermsHook.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/config/Formatter.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java Co-authored-by: William <will27528@gmail.com> * Fixed problem while updating display names. Changed a few method signature as requested in pr. Applied changes of pr. * Fixed problems after merging with upstream, fixed problem with player team color on join. * Update src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/packet/ScoreboardManager.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/packet/ScoreboardManager.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/packet/ScoreboardManager.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/config/Formatter.java Co-authored-by: William <will27528@gmail.com> * Update src/main/java/net/william278/velocitab/player/TabPlayer.java Co-authored-by: William <will27528@gmail.com> * Fix username replacement in scoreboard and code typo This commit resolves two issues. Firstly, changed the variable that we split the nametag on in `ScoreboardManager` from a hardcoded string to the player's specific username. This rectifies an issue where incorrect splitting occurred if the username wasn't exactly "%username%". Secondly, fixed a miswritten method call in `Formatter` from '..legacySection()' to '.legacySection()', correcting a syntax error. Lastly, removed superfluous replacement in `TabPlayer's` getNametag method as it was already handled in `ScoreboardManager`. --------- Co-authored-by: William <will27528@gmail.com>
This commit is contained in:
parent
8ae25521dd
commit
75d9f32010
@ -95,6 +95,7 @@ public class Velocitab {
|
||||
@Subscribe
|
||||
public void onProxyShutdown(@NotNull ProxyShutdownEvent event) {
|
||||
disableScoreboardManager();
|
||||
getLuckPermsHook().ifPresent(LuckPermsHook::close);
|
||||
logger.info("Successfully disabled Velocitab");
|
||||
}
|
||||
|
||||
@ -119,6 +120,12 @@ public class Velocitab {
|
||||
new File(dataDirectory.toFile(), "config.yml"),
|
||||
new Settings(this)
|
||||
).get();
|
||||
|
||||
settings.getNametags().values().stream()
|
||||
.filter(nametag -> !nametag.contains("%username%")).forEach(nametag -> {
|
||||
logger.warn("Nametag '" + nametag + "' does not contain %username% - removing");
|
||||
settings.getNametags().remove(nametag);
|
||||
});
|
||||
} catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
logger.error("Failed to load config file: " + e.getMessage(), e);
|
||||
}
|
||||
@ -156,7 +163,7 @@ public class Velocitab {
|
||||
}
|
||||
|
||||
private void disableScoreboardManager() {
|
||||
if (scoreboardManager !=null && settings.isSortPlayers()) {
|
||||
if (scoreboardManager != null && settings.isSortPlayers()) {
|
||||
scoreboardManager.unregisterPacket();
|
||||
}
|
||||
}
|
||||
@ -184,6 +191,10 @@ public class Velocitab {
|
||||
);
|
||||
}
|
||||
|
||||
public Optional<TabPlayer> getTabPlayer(String name) {
|
||||
return server.getPlayer(name).map(this::getTabPlayer);
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
final BrigadierCommand command = new VelocitabCommand(this).command();
|
||||
server.getCommandManager().register(
|
||||
|
@ -79,6 +79,11 @@ public enum Formatter {
|
||||
return formatter.apply(text, player, plugin);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String formatLegacySymbols(@NotNull String text, @NotNull TabPlayer player, @NotNull Velocitab plugin) {
|
||||
return LegacyComponentSerializer.legacySection()
|
||||
.serialize(format(text, player, plugin));
|
||||
}
|
||||
@NotNull
|
||||
public String escape(@NotNull String text) {
|
||||
return escaper.apply(text);
|
||||
|
@ -65,6 +65,10 @@ public enum Placeholder {
|
||||
}
|
||||
final String replaced = format;
|
||||
|
||||
if (!replaced.matches("%.*?%")) {
|
||||
return CompletableFuture.completedFuture(replaced);
|
||||
}
|
||||
|
||||
return plugin.getPAPIProxyBridgeHook()
|
||||
.map(hook -> hook.formatPlaceholders(replaced, player.getPlayer()))
|
||||
.orElse(CompletableFuture.completedFuture(replaced));
|
||||
|
@ -60,6 +60,11 @@ public class Settings {
|
||||
@YamlKey("formats")
|
||||
private Map<String, String> formats = Map.of("default", "&7[%server%] &f%prefix%%username%");
|
||||
|
||||
@Getter
|
||||
@YamlKey("nametags")
|
||||
@YamlComment("Nametag(s) to display above players' heads for each server group. To disable, set to empty")
|
||||
private Map<String, String> nametags = Map.of("default", "&f%prefix%%username%&f%suffix%");
|
||||
|
||||
@Getter
|
||||
@YamlComment("Which text formatter to use (MINEDOWN, MINIMESSAGE, or LEGACY)")
|
||||
@YamlKey("formatting_type")
|
||||
@ -165,6 +170,16 @@ public class Settings {
|
||||
formats.getOrDefault(serverGroup, "%username%"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNametag(@NotNull String serverGroup) {
|
||||
return StringEscapeUtils.unescapeJava(
|
||||
nametags.getOrDefault(serverGroup, ""));
|
||||
}
|
||||
|
||||
public boolean areNametagsEnabled() {
|
||||
return !nametags.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get display name for the server
|
||||
*
|
||||
|
@ -23,6 +23,7 @@ import com.velocitypowered.api.proxy.Player;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.event.EventSubscription;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import net.luckperms.api.model.group.Group;
|
||||
import net.luckperms.api.model.user.User;
|
||||
@ -42,11 +43,16 @@ public class LuckPermsHook extends Hook {
|
||||
|
||||
private int highestWeight = Role.DEFAULT_WEIGHT;
|
||||
private final LuckPerms api;
|
||||
private final EventSubscription<UserDataRecalculateEvent> event;
|
||||
|
||||
public LuckPermsHook(@NotNull Velocitab plugin) throws IllegalStateException {
|
||||
super(plugin);
|
||||
this.api = LuckPermsProvider.get();
|
||||
api.getEventBus().subscribe(plugin, UserDataRecalculateEvent.class, this::onLuckPermsGroupUpdate);
|
||||
event = api.getEventBus().subscribe(plugin, UserDataRecalculateEvent.class, this::onLuckPermsGroupUpdate);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
event.close();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -81,6 +87,7 @@ public class LuckPermsHook extends Hook {
|
||||
);
|
||||
tabList.replacePlayer(updatedPlayer);
|
||||
tabList.updatePlayer(updatedPlayer);
|
||||
tabList.updatePlayerDisplayName(updatedPlayer);
|
||||
})
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.schedule());
|
||||
|
@ -32,7 +32,7 @@ public class PAPIProxyBridgeHook extends Hook {
|
||||
|
||||
public PAPIProxyBridgeHook(@NotNull Velocitab plugin) {
|
||||
super(plugin);
|
||||
this.api = PlaceholderAPI.getInstance();
|
||||
this.api = PlaceholderAPI.createInstance();
|
||||
this.api.setCacheExpiry(Math.max(0, plugin.getSettings().getPapiCacheTime()));
|
||||
}
|
||||
|
||||
|
@ -21,15 +21,18 @@ package net.william278.velocitab.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.*;
|
||||
|
||||
@ -37,14 +40,14 @@ public class ScoreboardManager {
|
||||
|
||||
private PacketRegistration<UpdateTeamsPacket> packetRegistration;
|
||||
private final Velocitab plugin;
|
||||
private final Map<UUID, List<String>> createdTeams;
|
||||
private final Map<UUID, Map<String, String>> roleMappings;
|
||||
private final Set<TeamsPacketAdapter> versions;
|
||||
private final Map<UUID, String> createdTeams;
|
||||
private final Map<String, String> nametags;
|
||||
|
||||
public ScoreboardManager(@NotNull Velocitab velocitab) {
|
||||
this.plugin = velocitab;
|
||||
this.createdTeams = new HashMap<>();
|
||||
this.roleMappings = new HashMap<>();
|
||||
this.createdTeams = new ConcurrentHashMap<>();
|
||||
this.nametags = new ConcurrentHashMap<>();
|
||||
this.versions = new HashSet<>();
|
||||
this.registerVersions();
|
||||
}
|
||||
@ -64,44 +67,78 @@ public class ScoreboardManager {
|
||||
}
|
||||
|
||||
public void resetCache(@NotNull Player player) {
|
||||
createdTeams.remove(player.getUniqueId());
|
||||
roleMappings.remove(player.getUniqueId());
|
||||
String team = createdTeams.remove(player.getUniqueId());
|
||||
if (team != null) {
|
||||
dispatchGroupPacket(UpdateTeamsPacket.removeTeam(plugin, team), player);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRoles(@NotNull Player player, @NotNull Map<String, String> playerRoles) {
|
||||
public void updateRole(@NotNull Player player, @NotNull String role) {
|
||||
if (!player.isActive()) {
|
||||
plugin.getTabList().removeOfflinePlayer(player);
|
||||
return;
|
||||
}
|
||||
playerRoles.entrySet().stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
Map.Entry::getValue,
|
||||
Collectors.mapping(Map.Entry::getKey, Collectors.toList())
|
||||
))
|
||||
.forEach((role, players) -> updateRoles(player, role, players.toArray(new String[0])));
|
||||
|
||||
final String name = player.getUsername();
|
||||
final TabPlayer tabPlayer = plugin.getTabPlayer(player);
|
||||
tabPlayer.getNametag(plugin).thenAccept(nametag -> {
|
||||
String[] split = nametag.split(player.getUsername(), 2);
|
||||
String prefix = split[0];
|
||||
String suffix = split.length > 1 ? split[1] : "";
|
||||
|
||||
if (!createdTeams.getOrDefault(player.getUniqueId(), "").equals(role)) {
|
||||
createdTeams.computeIfAbsent(player.getUniqueId(), k -> role);
|
||||
this.nametags.put(role, prefix + ":::" + suffix);
|
||||
dispatchGroupPacket(UpdateTeamsPacket.create(plugin, role, "", prefix, suffix, name), player);
|
||||
} else if (!this.nametags.getOrDefault(role, "").equals(prefix + ":::" + suffix)) {
|
||||
this.nametags.put(role, prefix + ":::" + suffix);
|
||||
dispatchGroupPacket(UpdateTeamsPacket.changeNameTag(plugin, role, prefix, suffix), player);
|
||||
}
|
||||
}).exceptionally(e -> {
|
||||
plugin.log(Level.ERROR, "Failed to update role for " + player.getUsername(), e);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public void updateRoles(@NotNull Player player, @NotNull String role, @NotNull String... playerNames) {
|
||||
if (!player.isActive()) {
|
||||
plugin.getTabList().removeOfflinePlayer(player);
|
||||
|
||||
public void resendAllNameTags(Player player) {
|
||||
|
||||
if(!plugin.getSettings().areNametagsEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (!createdTeams.getOrDefault(player.getUniqueId(), List.of()).contains(role)) {
|
||||
dispatchPacket(UpdateTeamsPacket.create(plugin, role, playerNames), player);
|
||||
createdTeams.computeIfAbsent(player.getUniqueId(), k -> new ArrayList<>()).add(role);
|
||||
roleMappings.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()).put(player.getUsername(), role);
|
||||
} else {
|
||||
roleMappings.getOrDefault(player.getUniqueId(), Map.of())
|
||||
.entrySet().stream()
|
||||
.filter((entry) -> List.of(playerNames).contains(entry.getKey()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
|
||||
.forEach((playerName, oldRole) -> dispatchPacket(
|
||||
UpdateTeamsPacket.removeFromTeam(plugin, oldRole, playerName),
|
||||
player
|
||||
));
|
||||
dispatchPacket(UpdateTeamsPacket.addToTeam(plugin, role, playerNames), player);
|
||||
roleMappings.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()).put(player.getUsername(), role);
|
||||
|
||||
final Optional<ServerConnection> optionalServerConnection = player.getCurrentServer();
|
||||
if (optionalServerConnection.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegisteredServer serverInfo = optionalServerConnection.get().getServer();
|
||||
|
||||
List<RegisteredServer> siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName());
|
||||
|
||||
List<Player> players = siblings.stream().map(RegisteredServer::getPlayersConnected).flatMap(Collection::stream).toList();
|
||||
|
||||
players.forEach(p -> {
|
||||
if (p == player || !p.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String role = createdTeams.getOrDefault(p.getUniqueId(), "");
|
||||
if (role.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String nametag = nametags.getOrDefault(role, "");
|
||||
if (nametag.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] split = nametag.split(":::", 2);
|
||||
String prefix = split[0];
|
||||
String suffix = split.length > 1 ? split[1] : "";
|
||||
|
||||
dispatchPacket(UpdateTeamsPacket.create(plugin, role, "", prefix, suffix, p.getUsername()), player);
|
||||
});
|
||||
}
|
||||
|
||||
private void dispatchPacket(@NotNull UpdateTeamsPacket packet, @NotNull Player player) {
|
||||
@ -118,6 +155,29 @@ public class ScoreboardManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchGroupPacket(@NotNull UpdateTeamsPacket packet, @NotNull Player player) {
|
||||
Optional<ServerConnection> optionalServerConnection = player.getCurrentServer();
|
||||
|
||||
if (optionalServerConnection.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegisteredServer serverInfo = optionalServerConnection.get().getServer();
|
||||
|
||||
List<RegisteredServer> siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName());
|
||||
|
||||
siblings.forEach(s -> {
|
||||
s.getPlayersConnected().forEach(p -> {
|
||||
try {
|
||||
final ConnectedPlayer connectedPlayer = (ConnectedPlayer) p;
|
||||
connectedPlayer.getConnection().write(packet);
|
||||
} catch (Exception e) {
|
||||
plugin.log(Level.ERROR, "Failed to dispatch packet (is the client or server modded or using an illegal version?)", e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void registerPacket() {
|
||||
try {
|
||||
packetRegistration = PacketRegistration.of(UpdateTeamsPacket.class)
|
||||
|
@ -30,6 +30,7 @@ import net.william278.velocitab.Velocitab;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -61,18 +62,32 @@ public class UpdateTeamsPacket implements MinecraftPacket {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static UpdateTeamsPacket create(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String... teamMembers) {
|
||||
protected static UpdateTeamsPacket create(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String displayName, @Nullable String prefix, @Nullable String suffix, @NotNull String... teamMembers) {
|
||||
return new UpdateTeamsPacket(plugin)
|
||||
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
|
||||
.mode(UpdateMode.CREATE_TEAM)
|
||||
.displayName(displayName)
|
||||
.friendlyFlags(List.of(FriendlyFlag.CAN_HURT_FRIENDLY))
|
||||
.nameTagVisibility(NameTagVisibility.ALWAYS)
|
||||
.collisionRule(CollisionRule.ALWAYS)
|
||||
.color(getLastColor(prefix))
|
||||
.prefix(prefix == null ? "" : prefix)
|
||||
.suffix(suffix == null ? "" : suffix)
|
||||
.entities(Arrays.asList(teamMembers));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static UpdateTeamsPacket changeNameTag(@NotNull Velocitab plugin, @NotNull String teamName, @Nullable String prefix, @Nullable String suffix) {
|
||||
return new UpdateTeamsPacket(plugin)
|
||||
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
|
||||
.mode(UpdateMode.UPDATE_INFO)
|
||||
.displayName(teamName)
|
||||
.friendlyFlags(List.of(FriendlyFlag.CAN_HURT_FRIENDLY))
|
||||
.nameTagVisibility(NameTagVisibility.ALWAYS)
|
||||
.collisionRule(CollisionRule.ALWAYS)
|
||||
.color(15)
|
||||
.prefix("")
|
||||
.suffix("")
|
||||
.entities(Arrays.asList(teamMembers));
|
||||
.color(getLastColor(prefix))
|
||||
.prefix(prefix == null ? "" : prefix)
|
||||
.suffix(suffix == null ? "" : suffix);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -91,6 +106,64 @@ public class UpdateTeamsPacket implements MinecraftPacket {
|
||||
.entities(Arrays.asList(teamMembers));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static UpdateTeamsPacket removeTeam(@NotNull Velocitab plugin, @NotNull String teamName) {
|
||||
return new UpdateTeamsPacket(plugin)
|
||||
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
|
||||
.mode(UpdateMode.REMOVE_TEAM);
|
||||
}
|
||||
|
||||
public static int getLastColor(@Nullable String text) {
|
||||
if (text == null) {
|
||||
return 15;
|
||||
}
|
||||
int intvar = text.lastIndexOf("§");
|
||||
|
||||
if (intvar == -1 || intvar == text.length() - 1) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
String last = text.substring(intvar, intvar + 2);
|
||||
return TeamColor.getColorId(last.charAt(1));
|
||||
}
|
||||
|
||||
public enum TeamColor {
|
||||
BLACK('0', 0),
|
||||
DARK_BLUE('1', 1),
|
||||
DARK_GREEN('2', 2),
|
||||
DARK_AQUA('3', 3),
|
||||
DARK_RED('4', 4),
|
||||
DARK_PURPLE('5', 5),
|
||||
GOLD('6', 6),
|
||||
GRAY('7', 7),
|
||||
DARK_GRAY('8', 8),
|
||||
BLUE('9', 9),
|
||||
GREEN('a', 10),
|
||||
AQUA('b', 11),
|
||||
RED('c', 12),
|
||||
LIGHT_PURPLE('d', 13),
|
||||
YELLOW('e', 14),
|
||||
WHITE('f', 15),
|
||||
OBFUSCATED('k', 16),
|
||||
BOLD('l', 17),
|
||||
STRIKETHROUGH('m', 18),
|
||||
UNDERLINED('n', 19),
|
||||
ITALIC('o', 20),
|
||||
RESET('r', 21);
|
||||
|
||||
private final char colorChar;
|
||||
private final int id;
|
||||
|
||||
TeamColor(char colorChar, int id) {
|
||||
this.colorChar= colorChar;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static int getColorId(char var) {
|
||||
return Arrays.stream(values()).filter(color -> color.colorChar == var).map(c -> c.id).findFirst().orElse(15);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException("Operation not supported");
|
||||
|
@ -20,6 +20,7 @@
|
||||
package net.william278.velocitab.player;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.config.Placeholder;
|
||||
@ -36,8 +37,12 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
private final Player player;
|
||||
private final Role role;
|
||||
private final int highestWeight;
|
||||
@Getter
|
||||
private int headerIndex = 0;
|
||||
@Getter
|
||||
private int footerIndex = 0;
|
||||
@Getter
|
||||
private Component lastDisplayname;
|
||||
|
||||
public TabPlayer(@NotNull Player player, @NotNull Role role, int highestWeight) {
|
||||
this.player = player;
|
||||
@ -105,7 +110,15 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
public CompletableFuture<Component> getDisplayName(@NotNull Velocitab plugin) {
|
||||
final String serverGroup = plugin.getSettings().getServerGroup(getServerName());
|
||||
return Placeholder.replace(plugin.getSettings().getFormat(serverGroup), plugin, this)
|
||||
.thenApply(formatted -> plugin.getFormatter().format(formatted, this, plugin));
|
||||
.thenApply(formatted -> plugin.getFormatter().format(formatted, this, plugin))
|
||||
.thenApply(c -> this.lastDisplayname = c);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompletableFuture<String> getNametag(@NotNull Velocitab plugin) {
|
||||
final String serverGroup = plugin.getSettings().getServerGroup(getServerName());
|
||||
return Placeholder.replace(plugin.getSettings().getNametag(serverGroup), plugin, this)
|
||||
.thenApply(formatted -> plugin.getFormatter().formatLegacySymbols(formatted, this, plugin));
|
||||
|
||||
}
|
||||
|
||||
@ -113,18 +126,16 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
public String getTeamName(@NotNull Velocitab plugin) {
|
||||
return plugin.getSettings().getSortingElementList().stream()
|
||||
.map(element -> element.resolve(this, plugin))
|
||||
.collect(Collectors.joining("-"));
|
||||
.collect(Collectors.joining("-"))
|
||||
+ getPlayer().getUniqueId().toString().substring(0, 3);
|
||||
}
|
||||
|
||||
|
||||
public void sendHeaderAndFooter(@NotNull PlayerTabList tabList) {
|
||||
tabList.getHeader(this).thenAccept(header -> tabList.getFooter(this)
|
||||
.thenAccept(footer -> player.sendPlayerListHeaderAndFooter(header, footer)));
|
||||
}
|
||||
|
||||
public int getHeaderIndex() {
|
||||
return headerIndex;
|
||||
}
|
||||
|
||||
public void incrementHeaderIndex(@NotNull Velocitab plugin) {
|
||||
headerIndex++;
|
||||
if (headerIndex >= plugin.getSettings().getHeaderListSize(getServerGroup(plugin))) {
|
||||
@ -132,10 +143,6 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
}
|
||||
}
|
||||
|
||||
public int getFooterIndex() {
|
||||
return footerIndex;
|
||||
}
|
||||
|
||||
public void incrementFooterIndex(@NotNull Velocitab plugin) {
|
||||
footerIndex++;
|
||||
if (footerIndex >= plugin.getSettings().getFooterListSize(getServerGroup(plugin))) {
|
||||
@ -174,7 +181,7 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
? String.format("%0" + Integer.toString(orderSize).length() + "d", position)
|
||||
: String.valueOf(orderSize);
|
||||
}),
|
||||
SERVER_GROUP_NAME((player, plugin) -> player.getServerGroup(plugin));
|
||||
SERVER_GROUP_NAME(TabPlayer::getServerGroup);
|
||||
|
||||
private final BiFunction<TabPlayer, Velocitab, String> elementResolver;
|
||||
|
||||
|
@ -36,9 +36,7 @@ import net.william278.velocitab.config.Placeholder;
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
@ -67,7 +65,6 @@ public class PlayerTabList {
|
||||
final Player joined = event.getPlayer();
|
||||
plugin.getScoreboardManager().ifPresent(manager -> manager.resetCache(joined));
|
||||
|
||||
|
||||
// Remove the player from the tracking list if they are switching servers
|
||||
final RegisteredServer previousServer = event.getPreviousServer();
|
||||
if (previousServer == null) {
|
||||
@ -76,7 +73,7 @@ public class PlayerTabList {
|
||||
|
||||
// Get the servers in the group from the joined server name
|
||||
// If the server is not in a group, use fallback
|
||||
Optional<List<String>> serversInGroup = getSiblings(joined.getCurrentServer()
|
||||
Optional<List<String>> serversInGroup = getGroupNames(joined.getCurrentServer()
|
||||
.map(ServerConnection::getServerInfo)
|
||||
.map(ServerInfo::getName)
|
||||
.orElse("?"));
|
||||
@ -91,22 +88,17 @@ public class PlayerTabList {
|
||||
final TabPlayer tabPlayer = plugin.getTabPlayer(joined);
|
||||
players.add(tabPlayer);
|
||||
|
||||
|
||||
|
||||
// Update lists
|
||||
plugin.getServer().getScheduler()
|
||||
.buildTask(plugin, () -> {
|
||||
final TabList tabList = joined.getTabList();
|
||||
final Map<String, String> playerRoles = new HashMap<>();
|
||||
|
||||
for (TabPlayer player : players) {
|
||||
// Skip players on other servers if the setting is enabled
|
||||
if (plugin.getSettings().isOnlyListPlayersInSameGroup() && serversInGroup.isPresent()
|
||||
&& !serversInGroup.get().contains(player.getServerName())) {
|
||||
&& !serversInGroup.get().contains(player.getServerName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
playerRoles.put(player.getPlayer().getUsername(), player.getTeamName(plugin));
|
||||
tabList.getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(player.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresentOrElse(
|
||||
@ -114,13 +106,13 @@ public class PlayerTabList {
|
||||
() -> createEntry(player, tabList).thenAccept(tabList::addEntry)
|
||||
);
|
||||
addPlayerToTabList(player, tabPlayer);
|
||||
|
||||
player.sendHeaderAndFooter(this);
|
||||
|
||||
}
|
||||
|
||||
|
||||
plugin.getScoreboardManager().ifPresent(manager -> manager.setRoles(joined, playerRoles));
|
||||
plugin.getScoreboardManager().ifPresent(s -> {
|
||||
s.resendAllNameTags(joined);
|
||||
s.updateRole(joined, plugin.getTabPlayer(joined).getTeamName(plugin));
|
||||
});
|
||||
})
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.schedule();
|
||||
@ -149,11 +141,6 @@ public class PlayerTabList {
|
||||
() -> createEntry(newPlayer, player.getPlayer().getTabList())
|
||||
.thenAccept(entry -> player.getPlayer().getTabList().addEntry(entry))
|
||||
);
|
||||
plugin.getScoreboardManager().ifPresent(manager -> manager.updateRoles(
|
||||
player.getPlayer(),
|
||||
newPlayer.getTeamName(plugin),
|
||||
newPlayer.getPlayer().getUsername()
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
@ -177,6 +164,9 @@ public class PlayerTabList {
|
||||
}))
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.schedule();
|
||||
// Delete player team
|
||||
plugin.getScoreboardManager().ifPresent(manager -> manager.resetCache(event.getPlayer()));
|
||||
|
||||
}
|
||||
|
||||
// Replace a player in the tab list
|
||||
@ -192,16 +182,27 @@ public class PlayerTabList {
|
||||
return;
|
||||
}
|
||||
|
||||
players.forEach(player -> tabPlayer.getDisplayName(plugin).thenAccept(displayName -> {
|
||||
player.getPlayer().getTabList().getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(tabPlayer.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresent(entry -> entry.setDisplayName(displayName));
|
||||
plugin.getScoreboardManager().ifPresent(manager -> manager.updateRoles(
|
||||
player.getPlayer(),
|
||||
tabPlayer.getTeamName(plugin),
|
||||
tabPlayer.getPlayer().getUsername()
|
||||
));
|
||||
}));
|
||||
plugin.getScoreboardManager().ifPresent(manager -> manager.updateRole(
|
||||
tabPlayer.getPlayer(),
|
||||
tabPlayer.getTeamName(plugin)
|
||||
));
|
||||
}
|
||||
|
||||
public void updatePlayerDisplayName(TabPlayer tabPlayer) {
|
||||
Component lastDisplayName = tabPlayer.getLastDisplayname();
|
||||
tabPlayer.getDisplayName(plugin).thenAccept(displayName -> {
|
||||
if (displayName == null || displayName.equals(lastDisplayName)) return;
|
||||
|
||||
players.forEach(player ->
|
||||
player.getPlayer().getTabList().getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(tabPlayer.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresent(entry -> entry.setDisplayName(displayName)));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void updateDisplayNames() {
|
||||
players.forEach(this::updatePlayerDisplayName);
|
||||
}
|
||||
|
||||
public CompletableFuture<Component> getHeader(@NotNull TabPlayer player) {
|
||||
@ -231,6 +232,7 @@ public class PlayerTabList {
|
||||
this.updatePlayer(player);
|
||||
player.sendHeaderAndFooter(this);
|
||||
});
|
||||
updateDisplayNames();
|
||||
})
|
||||
.repeat(Math.max(200, updateRate), TimeUnit.MILLISECONDS)
|
||||
.schedule();
|
||||
@ -255,6 +257,7 @@ public class PlayerTabList {
|
||||
this.updatePlayer(player);
|
||||
player.sendHeaderAndFooter(this);
|
||||
});
|
||||
updateDisplayNames();
|
||||
}
|
||||
|
||||
}
|
||||
@ -269,7 +272,7 @@ public class PlayerTabList {
|
||||
* @return The servers in the same group as the given server, empty if the server is not in a group and fallback is disabled
|
||||
*/
|
||||
@NotNull
|
||||
public Optional<List<String>> getSiblings(String serverName) {
|
||||
public Optional<List<String>> getGroupNames(String serverName) {
|
||||
return plugin.getSettings().getServerGroups().values().stream()
|
||||
.filter(servers -> servers.contains(serverName))
|
||||
.findFirst()
|
||||
@ -285,6 +288,24 @@ public class PlayerTabList {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the servers in the same group as the given server, as an optional list of {@link ServerInfo}
|
||||
* <p>
|
||||
* If the server is not in a group, use the fallback group
|
||||
* If the fallback is disabled, return an empty optional
|
||||
*
|
||||
* @param serverName The server name
|
||||
* @return The servers in the same group as the given server, empty if the server is not in a group and fallback is disabled
|
||||
*/
|
||||
@NotNull
|
||||
public List<RegisteredServer> getGroupServers(String serverName) {
|
||||
return plugin.getServer().getAllServers().stream()
|
||||
.filter(server -> plugin.getSettings().getServerGroups().values().stream()
|
||||
.filter(servers -> servers.contains(serverName))
|
||||
.anyMatch(servers -> servers.contains(server.getServerInfo().getName())))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void proxyReload(@NotNull ProxyReloadEvent event) {
|
||||
plugin.loadSettings();
|
||||
|
Loading…
Reference in New Issue
Block a user