Reduce number of packets being sent, adjust logic

This commit is contained in:
William 2023-02-26 19:54:12 +00:00
parent de747bf3eb
commit 0a39899705
No known key found for this signature in database
6 changed files with 125 additions and 99 deletions

View File

@ -48,7 +48,7 @@ public class LuckPermsHook {
public void onLuckPermsGroupUpdate(@NotNull UserDataRecalculateEvent event) { public void onLuckPermsGroupUpdate(@NotNull UserDataRecalculateEvent event) {
plugin.getServer().getPlayer(event.getUser().getUniqueId()) plugin.getServer().getPlayer(event.getUser().getUniqueId())
.ifPresent(player -> plugin.getTabList().updatePlayer(new TabPlayer( .ifPresent(player -> plugin.getTabList().onPlayerRoleUpdate(new TabPlayer(
player, player,
getRoleFromMetadata(event.getData().getMetaData()), getRoleFromMetadata(event.getData().getMetaData()),
getHighestWeight() getHighestWeight()
@ -80,5 +80,4 @@ public class LuckPermsHook {
} }
} }

View File

@ -5,21 +5,54 @@ import dev.simplix.protocolize.api.PacketDirection;
import dev.simplix.protocolize.api.Protocol; import dev.simplix.protocolize.api.Protocol;
import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.Protocolize;
import net.william278.velocitab.Velocitab; import net.william278.velocitab.Velocitab;
import net.william278.velocitab.player.TabPlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.UUID; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors;
public class ScoreboardManager { public class ScoreboardManager {
private final Velocitab plugin; private final Velocitab plugin;
private final Map<UUID, List<String>> createdTeams;
private final ConcurrentHashMap<UUID, String> fauxTeams; private final Map<UUID, Map<String, String>> roleMappings;
public ScoreboardManager(@NotNull Velocitab velocitab) { public ScoreboardManager(@NotNull Velocitab velocitab) {
this.plugin = velocitab; this.plugin = velocitab;
this.fauxTeams = new ConcurrentHashMap<>(); this.createdTeams = new HashMap<>();
this.roleMappings = new HashMap<>();
}
public void resetCache(@NotNull Player player) {
createdTeams.remove(player.getUniqueId());
roleMappings.remove(player.getUniqueId());
}
public void sendTeamPackets(@NotNull Player player, @NotNull Map<Player, String> playerRoles) {
playerRoles.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry::getValue,
Collectors.mapping(entry -> entry.getKey().getUsername(), Collectors.toList())
))
.forEach((role, players) -> updateRoles(player, role, players.toArray(new String[0])));
}
public void updateRoles(@NotNull Player player, @NotNull String role, @NotNull String... playerNames) {
if (!createdTeams.getOrDefault(player.getUniqueId(), List.of()).contains(role)) {
dispatchPacket(UpdateTeamsPacket.create(role, playerNames), player);
createdTeams.computeIfAbsent(player.getUniqueId(), k -> new ArrayList<>()).add(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(oldRole, playerName), player));
dispatchPacket(UpdateTeamsPacket.addToTeam(role, playerNames), player);
roleMappings.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>()).put(player.getUsername(), role);
}
}
private void dispatchPacket(@NotNull UpdateTeamsPacket packet, @NotNull Player player) {
Protocolize.playerProvider().player(player.getUniqueId()).sendPacket(packet);
} }
public void registerPacket() { public void registerPacket() {
@ -35,40 +68,5 @@ public class ScoreboardManager {
} }
} }
public void setPlayerTeam(@NotNull TabPlayer player) {
removeTeam(player.getPlayer());
createTeam(player.getTeamName(), player.getPlayer());
}
private void createTeam(@NotNull String teamName, @NotNull Player member) {
final UUID uuid = member.getUniqueId();
try {
final UpdateTeamsPacket createTeamPacket = UpdateTeamsPacket.create(teamName, member.getUsername());
fauxTeams.put(uuid, teamName);
plugin.getServer().getAllPlayers().stream()
.map(Player::getUniqueId)
.map(Protocolize.playerProvider()::player)
.forEach(protocolPlayer -> protocolPlayer.sendPacket(createTeamPacket));
} catch (Exception e) {
plugin.log("Skipped setting team for " + member.getUsername());
}
}
public void removeTeam(@NotNull Player member) {
final UUID uuid = member.getUniqueId();
try {
final String teamName = fauxTeams.getOrDefault(uuid, null);
if (teamName != null) {
final UpdateTeamsPacket removeTeamPacket = UpdateTeamsPacket.remove(teamName);
plugin.getServer().getAllPlayers().stream()
.map(Player::getUniqueId)
.map(Protocolize.playerProvider()::player)
.forEach(protocolPlayer -> protocolPlayer.sendPacket(removeTeamPacket));
}
} catch (Exception e) {
plugin.log("Skipped removing team for " + member.getUsername());
}
fauxTeams.remove(uuid);
}
} }

View File

@ -45,7 +45,7 @@ public class UpdateTeamsPacket extends AbstractPacket {
private List<String> entities; private List<String> entities;
@NotNull @NotNull
public static UpdateTeamsPacket create(@NotNull String teamName, @NotNull String member) { public static UpdateTeamsPacket create(@NotNull String teamName, @NotNull String... teamMembers) {
return new UpdateTeamsPacket() return new UpdateTeamsPacket()
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName) .teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
.mode(UpdateMode.CREATE_TEAM) .mode(UpdateMode.CREATE_TEAM)
@ -56,14 +56,23 @@ public class UpdateTeamsPacket extends AbstractPacket {
.color(15) .color(15)
.prefix(getChatString("")) .prefix(getChatString(""))
.suffix(getChatString("")) .suffix(getChatString(""))
.entities(List.of(member)); .entities(Arrays.asList(teamMembers));
} }
@NotNull @NotNull
public static UpdateTeamsPacket remove(@NotNull String teamName) { public static UpdateTeamsPacket addToTeam(@NotNull String teamName, @NotNull String... teamMembers) {
return new UpdateTeamsPacket() return new UpdateTeamsPacket()
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName) .teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
.mode(UpdateMode.REMOVE_TEAM); .mode(UpdateMode.ADD_PLAYERS)
.entities(Arrays.asList(teamMembers));
}
@NotNull
public static UpdateTeamsPacket removeFromTeam(@NotNull String teamName, @NotNull String... teamMembers) {
return new UpdateTeamsPacket()
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
.mode(UpdateMode.REMOVE_PLAYERS)
.entities(Arrays.asList(teamMembers));
} }
@Override @Override

View File

@ -41,7 +41,7 @@ public class Role implements Comparable<Role> {
} }
@NotNull @NotNull
public String getStringComparableWeight(int highestWeight) { protected String getWeightString(int highestWeight) {
return String.format("%0" + (highestWeight + "").length() + "d", highestWeight - weight); return String.format("%0" + (highestWeight + "").length() + "d", highestWeight - weight);
} }
} }

View File

@ -43,7 +43,7 @@ public final class TabPlayer implements Comparable<TabPlayer> {
@NotNull @NotNull
public String getTeamName() { public String getTeamName() {
return role.getStringComparableWeight(highestWeight) + "-" + getServerName() + "-" + player.getUsername(); return role.getWeightString(highestWeight) + role.getName().map(name -> "-" + name).orElse("");
} }
public void sendHeaderAndFooter(@NotNull PlayerTabList tabList) { public void sendHeaderAndFooter(@NotNull PlayerTabList tabList) {

View File

@ -1,11 +1,11 @@
package net.william278.velocitab.tab; package net.william278.velocitab.tab;
import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent; import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.player.TabList;
import com.velocitypowered.api.proxy.player.TabListEntry; import com.velocitypowered.api.proxy.player.TabListEntry;
import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.api.proxy.server.ServerInfo;
import de.themoep.minedown.adventure.MineDown; import de.themoep.minedown.adventure.MineDown;
@ -15,7 +15,8 @@ import net.william278.velocitab.config.Placeholder;
import net.william278.velocitab.player.TabPlayer; import net.william278.velocitab.player.TabPlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Optional; import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -32,6 +33,8 @@ public class PlayerTabList {
@Subscribe @Subscribe
public void onPlayerJoin(@NotNull ServerPostConnectEvent event) { public void onPlayerJoin(@NotNull ServerPostConnectEvent event) {
final Player joined = event.getPlayer(); final Player joined = event.getPlayer();
plugin.getScoreboardManager().resetCache(joined);
// Remove the player from the tracking list if they are switching servers // Remove the player from the tracking list if they are switching servers
if (event.getPreviousServer() == null) { if (event.getPreviousServer() == null) {
players.removeIf(player -> player.getPlayer().getUniqueId().equals(joined.getUniqueId())); players.removeIf(player -> player.getPlayer().getUniqueId().equals(joined.getUniqueId()));
@ -46,14 +49,61 @@ public class PlayerTabList {
} }
// Add the player to the tracking list // Add the player to the tracking list
players.add(plugin.getTabPlayer(joined)); final TabPlayer tabPlayer = plugin.getTabPlayer(joined);
players.add(tabPlayer);
// Update the tab list of all players // Update lists
plugin.getServer().getScheduler().buildTask(plugin, this::updateList) plugin.getServer().getScheduler()
.buildTask(plugin, () -> {
final TabList tabList = joined.getTabList();
final Map<Player, String> playerRoles = new HashMap<>();
players.forEach(player -> {
playerRoles.put(player.getPlayer(), tabPlayer.getTeamName());
tabList.getEntries().stream()
.filter(e -> e.getProfile().getId().equals(player.getPlayer().getUniqueId())).findFirst()
.ifPresentOrElse(
entry -> entry.setDisplayName(player.getDisplayName(plugin)),
() -> tabList.addEntry(createEntry(player, tabList))
);
addPlayerToTabList(player, tabPlayer);
player.sendHeaderAndFooter(this);
});
plugin.getScoreboardManager().sendTeamPackets(joined, playerRoles);
})
.delay(500, TimeUnit.MILLISECONDS) .delay(500, TimeUnit.MILLISECONDS)
.schedule(); .schedule();
} }
@NotNull
private TabListEntry createEntry(@NotNull TabPlayer player, @NotNull TabList tabList) {
return TabListEntry.builder()
.profile(player.getPlayer().getGameProfile())
.displayName(player.getDisplayName(plugin))
.latency(0)
.tabList(tabList)
.build();
}
private void addPlayerToTabList(@NotNull TabPlayer player, @NotNull TabPlayer newPlayer) {
if (newPlayer.getPlayer().getUniqueId().equals(player.getPlayer().getUniqueId())) {
return;
}
player.getPlayer()
.getTabList().getEntries().stream()
.filter(e -> e.getProfile().getId().equals(newPlayer.getPlayer().getUniqueId())).findFirst()
.ifPresentOrElse(
entry -> entry.setDisplayName(newPlayer.getDisplayName(plugin)),
() -> player.getPlayer().getTabList()
.addEntry(createEntry(newPlayer, player.getPlayer().getTabList()))
);
plugin.getScoreboardManager().updateRoles(
player.getPlayer(),
newPlayer.getTeamName(),
newPlayer.getPlayer().getUsername()
);
}
@Subscribe @Subscribe
public void onPlayerQuit(@NotNull DisconnectEvent event) { public void onPlayerQuit(@NotNull DisconnectEvent event) {
// Remove the player from the tracking list // Remove the player from the tracking list
@ -63,56 +113,26 @@ public class PlayerTabList {
plugin.getServer().getAllPlayers().forEach(player -> player.getTabList().removeEntry(event.getPlayer().getUniqueId())); plugin.getServer().getAllPlayers().forEach(player -> player.getTabList().removeEntry(event.getPlayer().getUniqueId()));
// Update the tab list of all players // Update the tab list of all players
plugin.getServer().getScheduler().buildTask(plugin, () -> {
plugin.getScoreboardManager().removeTeam(event.getPlayer());
updateList();
})
.delay(500, TimeUnit.MILLISECONDS)
.schedule();
}
public void updatePlayer(@NotNull TabPlayer tabPlayer) {
plugin.getServer().getScheduler() plugin.getServer().getScheduler()
.buildTask(plugin, () -> { .buildTask(plugin, () -> players.forEach(player -> {
// Update the player's team sorting player.getPlayer().getTabList().removeEntry(event.getPlayer().getUniqueId());
players.remove(tabPlayer); player.sendHeaderAndFooter(this);
players.add(tabPlayer); }))
plugin.getScoreboardManager().setPlayerTeam(tabPlayer);
updateList();
})
.delay(500, TimeUnit.MILLISECONDS) .delay(500, TimeUnit.MILLISECONDS)
.schedule(); .schedule();
} }
private void updateList() { public void onPlayerRoleUpdate(@NotNull TabPlayer tabPlayer) {
final ImmutableList<TabPlayer> players = ImmutableList.copyOf(this.players); plugin.getServer().getScheduler()
players.forEach(player -> { .buildTask(plugin, () -> players.forEach(player -> {
player.sendHeaderAndFooter(this); player.getPlayer().getTabList().getEntries().stream()
.filter(e -> e.getProfile().getId().equals(tabPlayer.getPlayer().getUniqueId())).findFirst()
// Fill the tab list with the players .ifPresent(entry -> entry.setDisplayName(tabPlayer.getDisplayName(plugin)));
players.forEach(listedPlayer -> { plugin.getScoreboardManager().updateRoles(player.getPlayer(),
final Optional<TabListEntry> current = player.getPlayer().getTabList().getEntries().stream() tabPlayer.getTeamName(), tabPlayer.getPlayer().getUsername());
.filter(entry -> entry.getProfile().getId().equals(listedPlayer.getPlayer().getUniqueId())) }))
.findFirst(); .delay(500, TimeUnit.MILLISECONDS)
current.ifPresentOrElse( .schedule();
entry -> entry.setDisplayName(listedPlayer.getDisplayName(plugin)),
() -> player.getPlayer().getTabList().addEntry(TabListEntry.builder()
.profile(listedPlayer.getPlayer().getGameProfile())
.displayName(listedPlayer.getDisplayName(plugin))
.latency(0)
.tabList(player.getPlayer().getTabList())
.build()));
plugin.getScoreboardManager().setPlayerTeam(listedPlayer);
});
// Remove players in the tab list that are not in the players list
player.getPlayer().getTabList().getEntries().stream()
.filter(entry -> players.stream()
.noneMatch(listedPlayer -> listedPlayer.getPlayer().getUniqueId().equals(entry.getProfile().getId())))
.forEach(entry -> player.getPlayer().getTabList().removeEntry(entry.getProfile().getId()));
});
} }
@NotNull @NotNull