forked from Upstream/Velocitab
Delayed "real" player removing, spoofed user fixes, sort by server
This commit is contained in:
parent
6caf720b5d
commit
500c647ecc
@ -18,14 +18,19 @@ dependencies {
|
||||
compileOnly 'com.velocitypowered:velocity-api:3.1.1'
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
|
||||
implementation 'org.apache.commons:commons-text:1.10.0'
|
||||
implementation 'net.william278:Annotaml:2.0.1'
|
||||
implementation 'dev.dejvokep:boosted-yaml:1.3.1'
|
||||
implementation 'de.themoep:minedown-adventure:1.7.1-SNAPSHOT'
|
||||
|
||||
annotationProcessor 'com.velocitypowered:velocity-api:3.1.1'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate 'org.apache.commons.text', 'net.william278.husktowns.libraries.commons.text'
|
||||
relocate 'org.apache.commons.lang3', 'net.william278.husktowns.libraries.commons.lang3'
|
||||
relocate 'de.themoep', 'net.william278.velocitab.libraries'
|
||||
relocate 'dev.dejvokep.boostedyaml', 'net.william278.velocitab.libraries'
|
||||
relocate 'net.william278.annotaml', 'net.william278.velocitab.libraries.annotaml'
|
||||
|
||||
dependencies {
|
||||
|
@ -53,6 +53,7 @@ public class Velocitab {
|
||||
loadSettings();
|
||||
loadHooks();
|
||||
prepareTabList();
|
||||
logger.info("Successfully enabled Velocitab v" + BuildConstants.VERSION);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -84,12 +85,18 @@ public class Velocitab {
|
||||
|
||||
// If LuckPerms is present, load the hook
|
||||
try {
|
||||
luckPerms = new LuckPermsHook();
|
||||
luckPerms = new LuckPermsHook(this);
|
||||
server.getEventManager().register(this, luckPerms);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("LuckPerms was not loaded: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PlayerTabList getTabList() {
|
||||
return tabList;
|
||||
}
|
||||
|
||||
private void prepareTabList() {
|
||||
this.tabList = new PlayerTabList(this);
|
||||
server.getEventManager().register(this, new PlayerTabList(this));
|
||||
|
@ -2,7 +2,6 @@ package net.william278.velocitab.config;
|
||||
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -15,20 +14,19 @@ public enum Placeholder {
|
||||
|
||||
PLAYERS_ONLINE((plugin, player) -> Integer.toString(plugin.getServer().getPlayerCount())),
|
||||
MAX_PLAYERS_ONLINE((plugin, player) -> Integer.toString(plugin.getServer().getConfiguration().getShowMaxPlayers())),
|
||||
LOCAL_PLAYERS_ONLINE((plugin, player) -> player.player().getCurrentServer()
|
||||
LOCAL_PLAYERS_ONLINE((plugin, player) -> player.getPlayer().getCurrentServer()
|
||||
.map(ServerConnection::getServer)
|
||||
.map(RegisteredServer::getPlayersConnected)
|
||||
.map(players -> Integer.toString(players.size()))
|
||||
.orElse("")),
|
||||
CURRENT_DATE((plugin, player) -> DateTimeFormatter.ofPattern("dd MMM yyyy").format(LocalDateTime.now())),
|
||||
CURRENT_TIME((plugin, player) -> DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now())),
|
||||
USERNAME((plugin, player) -> player.player().getUsername()),
|
||||
SERVER((plugin, player) -> player.player().getCurrentServer()
|
||||
.map(ServerConnection::getServerInfo)
|
||||
.map(ServerInfo::getName).orElse("")),
|
||||
PING((plugin, player) -> Long.toString(player.player().getPing())),
|
||||
PREFIX((plugin, player) -> player.role().getPrefix().orElse("")),
|
||||
SUFFIX((plugin, player) -> player.role().getSuffix().orElse(""));
|
||||
USERNAME((plugin, player) -> player.getPlayer().getUsername()),
|
||||
SERVER((plugin, player) -> player.getServerName()),
|
||||
PING((plugin, player) -> Long.toString(player.getPlayer().getPing())),
|
||||
PREFIX((plugin, player) -> player.getRole().getPrefix().orElse("")),
|
||||
SUFFIX((plugin, player) -> player.getRole().getSuffix().orElse("")),
|
||||
ROLE((plugin, player) -> player.getRole().getName().orElse(""));
|
||||
|
||||
private final BiFunction<Velocitab, TabPlayer, String> formatter;
|
||||
|
||||
|
@ -1,46 +1,42 @@
|
||||
package net.william278.velocitab.config;
|
||||
|
||||
import net.william278.annotaml.YamlComment;
|
||||
import net.william278.annotaml.YamlFile;
|
||||
import net.william278.annotaml.YamlKey;
|
||||
import net.william278.velocitab.BuildConstants;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@YamlFile(header = "Velocitab Config File")
|
||||
@YamlFile(header = """
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Velocitab Config ┃
|
||||
┃ Developed by William278 ┃
|
||||
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┗╸ Placeholders: %players_online%, %max_players_online%, %local_players_online%, %current_date%, %current_time%, %username%, %server%, %ping%, %prefix%, %suffix%, %role%""")
|
||||
public class Settings {
|
||||
|
||||
@YamlKey("tab_list.header")
|
||||
private String header = "Welcome to the server!";
|
||||
|
||||
@YamlKey("tab_list.footer")
|
||||
private String footer = "Welcome to the server!";
|
||||
|
||||
@YamlKey("tab_list.format")
|
||||
private String format;
|
||||
|
||||
@YamlComment("Use LuckPerms for tab list formatting (if installed)")
|
||||
@YamlKey("use_luckperms")
|
||||
private boolean useLuckPerms = true;
|
||||
@YamlKey("header")
|
||||
private String header = "&rainbow&Running Velocitab v" + BuildConstants.VERSION + " by William278";
|
||||
@YamlKey("footer")
|
||||
private String footer = "[There are currently %players_online%/%max_players_online% players online](gray)";
|
||||
@YamlKey("format")
|
||||
private String format = "&7[%server%] &f%prefix%%username%";
|
||||
|
||||
private Settings() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getHeader() {
|
||||
return header;
|
||||
return StringEscapeUtils.unescapeJava(header);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFooter() {
|
||||
return footer;
|
||||
return StringEscapeUtils.unescapeJava(footer);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public boolean isUseLuckPerms() {
|
||||
return useLuckPerms;
|
||||
return StringEscapeUtils.unescapeJava(format);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
package net.william278.velocitab.luckperms;
|
||||
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
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.user.UserDataRecalculateEvent;
|
||||
import net.luckperms.api.model.group.Group;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.player.Role;
|
||||
import net.william278.velocitab.tab.PlayerTabList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -15,9 +19,11 @@ import java.util.UUID;
|
||||
|
||||
public class LuckPermsHook {
|
||||
|
||||
private final Velocitab plugin;
|
||||
private final LuckPerms api;
|
||||
|
||||
public LuckPermsHook() throws IllegalStateException {
|
||||
public LuckPermsHook(@NotNull Velocitab plugin) throws IllegalStateException {
|
||||
this.plugin = plugin;
|
||||
this.api = LuckPermsProvider.get();
|
||||
}
|
||||
|
||||
@ -36,6 +42,16 @@ public class LuckPermsHook {
|
||||
return Role.DEFAULT_ROLE;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onLuckPermsGroupUpdate(@NotNull UserDataRecalculateEvent event) {
|
||||
plugin.getServer().getPlayer(event.getUser().getUniqueId()).ifPresent(player -> {
|
||||
final PlayerTabList tabList = plugin.getTabList();
|
||||
tabList.removePlayer(player);
|
||||
tabList.addPlayer(plugin.getTabPlayer(player));
|
||||
tabList.refreshHeaderAndFooter();
|
||||
});
|
||||
}
|
||||
|
||||
private OptionalInt getWeight(@Nullable String groupName) {
|
||||
final Group group;
|
||||
if (groupName == null || (group = api.getGroupManager().getGroup(groupName)) == null) {
|
||||
|
@ -42,6 +42,6 @@ public class Role implements Comparable<Role> {
|
||||
|
||||
@NotNull
|
||||
public String getStringComparableWeight() {
|
||||
return String.format("%05d", weight);
|
||||
return String.format("%03d", weight);
|
||||
}
|
||||
}
|
||||
|
@ -11,20 +11,61 @@ import net.william278.velocitab.config.Placeholder;
|
||||
import net.william278.velocitab.tab.PlayerTabList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record TabPlayer(@NotNull Player player, @NotNull Role role) implements Comparable<TabPlayer> {
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
private static final int DEFAULT_LATENCY = 3;
|
||||
private final Player player;
|
||||
private final Role role;
|
||||
private final GameProfile profile;
|
||||
|
||||
public TabPlayer(@NotNull Player player, @NotNull Role role) {
|
||||
this.player = player;
|
||||
this.role = role;
|
||||
final String profileName = role.getStringComparableWeight() + "-" + getServerName() + "-" + player.getUsername();
|
||||
this.profile = new GameProfile(
|
||||
new UUID(0, new Random().nextLong()),
|
||||
profileName.length() > 16 ? profileName.substring(0, 16) : profileName,
|
||||
player.getGameProfileProperties()
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Component getFormattedEntry(@NotNull Velocitab plugin) {
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GameProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getServerName() {
|
||||
return player.getCurrentServer()
|
||||
.map(serverConnection -> serverConnection.getServerInfo().getName())
|
||||
.orElse("Unknown");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Component getDisplayName(@NotNull Velocitab plugin) {
|
||||
return new MineDown(Placeholder.format(plugin.getSettings().getFormat(), plugin, this)).toComponent();
|
||||
}
|
||||
|
||||
private TabListEntry getEntry(@NotNull Velocitab plugin, @NotNull TabList list) {
|
||||
private TabListEntry getEntry(@NotNull Velocitab plugin, @NotNull TabList tabList) {
|
||||
return TabListEntry.builder()
|
||||
.displayName(getFormattedEntry(plugin))
|
||||
.latency((int) player.getPing())
|
||||
.tabList(list)
|
||||
.profile(new GameProfile(player.getUniqueId(),
|
||||
role.getStringComparableWeight() + " " + player.getUsername(),
|
||||
player.getGameProfileProperties()))
|
||||
.displayName(getDisplayName(plugin))
|
||||
.latency(DEFAULT_LATENCY)
|
||||
.profile(profile)
|
||||
.tabList(tabList)
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -34,10 +75,19 @@ public record TabPlayer(@NotNull Player player, @NotNull Role role) implements C
|
||||
|
||||
public void addPlayer(@NotNull TabPlayer player, @NotNull Velocitab plugin) {
|
||||
this.player.getTabList().addEntry(player.getEntry(plugin, this.player.getTabList()));
|
||||
removeUuidPlayer(plugin, player.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
public void removePlayer(@NotNull TabPlayer player) {
|
||||
this.player.getTabList().removeEntry(player.player().getUniqueId());
|
||||
public void removePlayer(@NotNull TabPlayer player, @NotNull Velocitab plugin) {
|
||||
this.player.getTabList().removeEntry(player.getProfile().getId());
|
||||
removeUuidPlayer(plugin, player.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
public void removeUuidPlayer(@NotNull Velocitab plugin, @NotNull UUID... uuid) {
|
||||
plugin.getServer().getScheduler()
|
||||
.buildTask(plugin, () -> Arrays.stream(uuid).forEach(this.player.getTabList()::removeEntry))
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.schedule();
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PlayerTabList {
|
||||
private final Velocitab plugin;
|
||||
@ -24,6 +25,31 @@ public class PlayerTabList {
|
||||
this.players = new ArrayList<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Subscribe
|
||||
public void onPlayerJoin(@NotNull ServerPostConnectEvent event) {
|
||||
final TabPlayer player = plugin.getTabPlayer(event.getPlayer());
|
||||
|
||||
// Reset existing tab list
|
||||
player.getPlayer().getTabList().clearHeaderAndFooter();
|
||||
player.getPlayer().getTabList().getEntries().clear();
|
||||
|
||||
// Show existing list to new player
|
||||
players.forEach(listPlayer -> player.addPlayer(listPlayer, plugin));
|
||||
addPlayer(player);
|
||||
refreshHeaderAndFooter();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerQuit(@NotNull DisconnectEvent event) {
|
||||
try {
|
||||
removePlayer(event.getPlayer());
|
||||
refreshHeaderAndFooter();
|
||||
} catch (Exception ignored) {
|
||||
// Ignore when server shutting down
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Component getHeader(@NotNull TabPlayer player) {
|
||||
return new MineDown(Placeholder.format(plugin.getSettings().getHeader(), plugin, player)).toComponent();
|
||||
@ -34,35 +60,22 @@ public class PlayerTabList {
|
||||
return new MineDown(Placeholder.format(plugin.getSettings().getFooter(), plugin, player)).toComponent();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Subscribe
|
||||
public void onPlayerJoin(@NotNull ServerPostConnectEvent event) {
|
||||
final TabPlayer player = plugin.getTabPlayer(event.getPlayer());
|
||||
|
||||
// Show existing list to new player
|
||||
players.forEach(listPlayer -> player.addPlayer(listPlayer, plugin));
|
||||
|
||||
// Update list for all players with new player
|
||||
// Add a new tab player to the list and update for online players
|
||||
public void addPlayer(@NotNull TabPlayer player) {
|
||||
players.add(player);
|
||||
players.forEach(tabPlayer -> {
|
||||
tabPlayer.addPlayer(player, plugin);
|
||||
tabPlayer.sendHeaderAndFooter(this);
|
||||
});
|
||||
players.forEach(tabPlayer -> tabPlayer.addPlayer(player, plugin));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerQuit(@NotNull DisconnectEvent event) {
|
||||
final Player quitPlayer = event.getPlayer();
|
||||
public void removePlayer(@NotNull Player playerToRemove) {
|
||||
final Optional<TabPlayer> quitTabPlayer = players.stream()
|
||||
.filter(player -> player.player().equals(quitPlayer)).findFirst();
|
||||
.filter(player -> player.getPlayer().equals(playerToRemove)).findFirst();
|
||||
if (quitTabPlayer.isPresent()) {
|
||||
players.remove(quitTabPlayer.get());
|
||||
players.forEach(tabPlayer -> {
|
||||
tabPlayer.removePlayer(quitTabPlayer.get());
|
||||
tabPlayer.sendHeaderAndFooter(this);
|
||||
});
|
||||
players.forEach(tabPlayer -> tabPlayer.removePlayer(quitTabPlayer.get(), plugin));
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshHeaderAndFooter() {
|
||||
players.forEach(tabPlayer -> tabPlayer.sendHeaderAndFooter(this));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user