mappings = new ArrayList<>();
- public PacketRegistration packetSupplier(final @NotNull Supplier
packetSupplier) {
- this.packetSupplier = packetSupplier;
- return this;
+ public PacketRegistration
packetSupplier(final @NotNull Supplier
packetSupplier) {
+ this.packetSupplier = packetSupplier;
+ return this;
+ }
+
+ public PacketRegistration
direction(final ProtocolUtils.Direction direction) {
+ this.direction = direction;
+ return this;
+ }
+
+ public PacketRegistration
stateRegistry(final @NotNull StateRegistry stateRegistry) {
+ this.stateRegistry = stateRegistry;
+ return this;
+ }
+
+ public PacketRegistration
mapping(
+ final int id,
+ final ProtocolVersion version,
+ final boolean encodeOnly
+ ) {
+ try {
+ final StateRegistry.PacketMapping mapping = (StateRegistry.PacketMapping) PACKET_MAPPING$map.invoke(
+ id, version, encodeOnly);
+ this.mappings.add(mapping);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
}
+ return this;
+ }
- public PacketRegistration
direction(final ProtocolUtils.Direction direction) {
- this.direction = direction;
- return this;
+ public void register() {
+ try {
+ final StateRegistry.PacketRegistry packetRegistry = direction == ProtocolUtils.Direction.CLIENTBOUND
+ ? (StateRegistry.PacketRegistry) STATE_REGISTRY$clientBound.invoke(stateRegistry)
+ : (StateRegistry.PacketRegistry) STATE_REGISTRY$serverBound.invoke(stateRegistry);
+
+ PACKET_REGISTRY$register.invoke(
+ packetRegistry,
+ packetClass,
+ packetSupplier,
+ mappings.toArray(StateRegistry.PacketMapping[]::new)
+ );
+
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
}
+ }
- public PacketRegistration
stateRegistry(final @NotNull StateRegistry stateRegistry) {
- this.stateRegistry = stateRegistry;
- return this;
+ @SuppressWarnings("unchecked")
+ public void unregister() {
+ try {
+ final StateRegistry.PacketRegistry packetRegistry = direction == ProtocolUtils.Direction.CLIENTBOUND
+ ? (StateRegistry.PacketRegistry) STATE_REGISTRY$clientBound.invoke(stateRegistry)
+ : (StateRegistry.PacketRegistry) STATE_REGISTRY$serverBound.invoke(stateRegistry);
+
+ Map versions = (Map) PACKET_REGISTRY$versions.invoke(packetRegistry);
+ versions.forEach((protocolVersion, protocolRegistry) -> {
+ try {
+ IntObjectMap> packetIdToSupplier = (IntObjectMap>) PACKET_REGISTRY$packetIdToSupplier.invoke(protocolRegistry);
+ Object2IntMap> packetClassToId = (Object2IntMap>) PACKET_REGISTRY$packetClassToId.invoke(protocolRegistry);
+ packetIdToSupplier.keySet().stream()
+ .filter(supplier -> packetIdToSupplier.get(supplier).get().getClass().equals(packetClass))
+ .forEach(packetIdToSupplier::remove);
+ packetClassToId.values().intStream()
+ .filter(id -> Objects.equals(packetClassToId.getInt(packetClass), id))
+ .forEach(packetClassToId::removeInt);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ });
+
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
}
+ }
- public PacketRegistration mapping(
- final int id,
- final ProtocolVersion version,
- final boolean encodeOnly
- ) {
- try {
- final StateRegistry.PacketMapping mapping = (StateRegistry.PacketMapping) PACKET_MAPPING$map.invoke(
- id, version, encodeOnly);
- this.mappings.add(mapping);
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- return this;
+ public static
PacketRegistration
of(Class
packetClass) {
+ return new PacketRegistration<>(packetClass);
+ }
+
+ private PacketRegistration(final @NotNull Class
packetClass) {
+ this.packetClass = packetClass;
+ }
+
+ private static final MethodHandle STATE_REGISTRY$clientBound;
+ private static final MethodHandle STATE_REGISTRY$serverBound;
+ private static final MethodHandle PACKET_REGISTRY$register;
+ private static final MethodHandle PACKET_REGISTRY$packetIdToSupplier;
+ private static final MethodHandle PACKET_REGISTRY$packetClassToId;
+ private static final MethodHandle PACKET_REGISTRY$versions;
+ private static final MethodHandle PACKET_MAPPING$map;
+
+ static {
+ final MethodHandles.Lookup lookup = MethodHandles.lookup();
+ try {
+ final MethodHandles.Lookup stateRegistryLookup = MethodHandles.privateLookupIn(StateRegistry.class, lookup);
+ STATE_REGISTRY$clientBound = stateRegistryLookup.findGetter(StateRegistry.class, "clientbound", StateRegistry.PacketRegistry.class);
+ STATE_REGISTRY$serverBound = stateRegistryLookup.findGetter(StateRegistry.class, "serverbound", StateRegistry.PacketRegistry.class);
+
+ final MethodType mapType = MethodType.methodType(StateRegistry.PacketMapping.class, Integer.TYPE, ProtocolVersion.class, Boolean.TYPE);
+ PACKET_MAPPING$map = stateRegistryLookup.findStatic(StateRegistry.class, "map", mapType);
+
+ final MethodHandles.Lookup packetRegistryLookup = MethodHandles.privateLookupIn(StateRegistry.PacketRegistry.class, lookup);
+ final MethodType registerType = MethodType.methodType(void.class, Class.class, Supplier.class, StateRegistry.PacketMapping[].class);
+ PACKET_REGISTRY$register = packetRegistryLookup.findVirtual(StateRegistry.PacketRegistry.class, "register", registerType);
+ PACKET_REGISTRY$versions = packetRegistryLookup.findGetter(StateRegistry.PacketRegistry.class, "versions", Map.class);
+
+ final MethodHandles.Lookup protocolRegistryLookup = MethodHandles.privateLookupIn(StateRegistry.PacketRegistry.ProtocolRegistry.class, lookup);
+ PACKET_REGISTRY$packetIdToSupplier = protocolRegistryLookup.findGetter(StateRegistry.PacketRegistry.ProtocolRegistry.class, "packetIdToSupplier", IntObjectMap.class);
+ PACKET_REGISTRY$packetClassToId = protocolRegistryLookup.findGetter(StateRegistry.PacketRegistry.ProtocolRegistry.class, "packetClassToId", Object2IntMap.class);
+
+
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
}
+ }
- public void register() {
- try {
- final StateRegistry.PacketRegistry packetRegistry = direction == ProtocolUtils.Direction.CLIENTBOUND
- ? (StateRegistry.PacketRegistry) STATE_REGISTRY$clientBound.invoke(stateRegistry)
- : (StateRegistry.PacketRegistry) STATE_REGISTRY$serverBound.invoke(stateRegistry);
-
- PACKET_REGISTRY$register.invoke(
- packetRegistry,
- packetClass,
- packetSupplier,
- mappings.toArray(StateRegistry.PacketMapping[]::new)
- );
-
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- @SuppressWarnings("unchecked")
- public void unregister() {
- try {
- final StateRegistry.PacketRegistry packetRegistry = direction == ProtocolUtils.Direction.CLIENTBOUND
- ? (StateRegistry.PacketRegistry) STATE_REGISTRY$clientBound.invoke(stateRegistry)
- : (StateRegistry.PacketRegistry) STATE_REGISTRY$serverBound.invoke(stateRegistry);
-
- Map versions = (Map) PACKET_REGISTRY$versions.invoke(packetRegistry);
- versions.forEach((protocolVersion, protocolRegistry) -> {
- try {
- IntObjectMap> packetIdToSupplier = (IntObjectMap>) PACKET_REGISTRY$packetIdToSupplier.invoke(protocolRegistry);
- Object2IntMap> packetClassToId = (Object2IntMap>) PACKET_REGISTRY$packetClassToId.invoke(protocolRegistry);
- packetIdToSupplier.keySet().stream()
- .filter(supplier -> packetIdToSupplier.get(supplier).get().getClass().equals(packetClass))
- .forEach(packetIdToSupplier::remove);
- packetClassToId.values().intStream()
- .filter(id -> Objects.equals(packetClassToId.getInt(packetClass), id))
- .forEach(packetClassToId::removeInt);
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- });
-
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- public static PacketRegistration
of(Class
packetClass) {
- return new PacketRegistration<>(packetClass);
- }
-
- private PacketRegistration(final @NotNull Class
packetClass) {
- this.packetClass = packetClass;
- }
-
- private static final MethodHandle STATE_REGISTRY$clientBound;
- private static final MethodHandle STATE_REGISTRY$serverBound;
- private static final MethodHandle PACKET_REGISTRY$register;
- private static final MethodHandle PACKET_REGISTRY$packetIdToSupplier;
- private static final MethodHandle PACKET_REGISTRY$packetClassToId;
- private static final MethodHandle PACKET_REGISTRY$versions;
- private static final MethodHandle PACKET_MAPPING$map;
-
-
-
-
- static {
- final MethodHandles.Lookup lookup = MethodHandles.lookup();
- try {
- final MethodHandles.Lookup stateRegistryLookup = MethodHandles.privateLookupIn(StateRegistry.class, lookup);
- STATE_REGISTRY$clientBound = stateRegistryLookup.findGetter(StateRegistry.class, "clientbound", StateRegistry.PacketRegistry.class);
- STATE_REGISTRY$serverBound = stateRegistryLookup.findGetter(StateRegistry.class, "serverbound", StateRegistry.PacketRegistry.class);
-
- final MethodType mapType = MethodType.methodType(StateRegistry.PacketMapping.class, Integer.TYPE, ProtocolVersion.class, Boolean.TYPE);
- PACKET_MAPPING$map = stateRegistryLookup.findStatic(StateRegistry.class, "map", mapType);
-
- final MethodHandles.Lookup packetRegistryLookup = MethodHandles.privateLookupIn(StateRegistry.PacketRegistry.class, lookup);
- final MethodType registerType = MethodType.methodType(void.class, Class.class, Supplier.class, StateRegistry.PacketMapping[].class);
- PACKET_REGISTRY$register = packetRegistryLookup.findVirtual(StateRegistry.PacketRegistry.class, "register", registerType);
- PACKET_REGISTRY$versions = packetRegistryLookup.findGetter(StateRegistry.PacketRegistry.class, "versions", Map.class);
-
- final MethodHandles.Lookup protocolRegistryLookup = MethodHandles.privateLookupIn(StateRegistry.PacketRegistry.ProtocolRegistry.class, lookup);
- PACKET_REGISTRY$packetIdToSupplier = protocolRegistryLookup.findGetter(StateRegistry.PacketRegistry.ProtocolRegistry.class, "packetIdToSupplier", IntObjectMap.class);
- PACKET_REGISTRY$packetClassToId = protocolRegistryLookup.findGetter(StateRegistry.PacketRegistry.ProtocolRegistry.class, "packetClassToId", Object2IntMap.class);
-
-
- } catch (Throwable e) {
- throw new RuntimeException(e);
- }
- }
}
diff --git a/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java b/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java
index 4dd339a..50097e1 100644
--- a/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java
+++ b/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java
@@ -30,20 +30,38 @@ import java.util.List;
import java.util.Set;
/**
- * Adapter for handling the UpdateTeamsPacket for Minecraft 1.13+
+ * Adapter for handling the UpdateTeamsPacket for Minecraft 1.13.2+
*/
@SuppressWarnings("DuplicatedCode")
public class Protocol403Adapter extends TeamsPacketAdapter {
public Protocol403Adapter() {
super(Set.of(ProtocolVersion.MINECRAFT_1_13_2,
+ ProtocolVersion.MINECRAFT_1_14,
+ ProtocolVersion.MINECRAFT_1_14_1,
+ ProtocolVersion.MINECRAFT_1_14_2,
+ ProtocolVersion.MINECRAFT_1_14_3,
ProtocolVersion.MINECRAFT_1_14_4,
+ ProtocolVersion.MINECRAFT_1_15,
+ ProtocolVersion.MINECRAFT_1_15_1,
ProtocolVersion.MINECRAFT_1_15_2,
+ ProtocolVersion.MINECRAFT_1_16,
+ ProtocolVersion.MINECRAFT_1_16_1,
+ ProtocolVersion.MINECRAFT_1_16_2,
+ ProtocolVersion.MINECRAFT_1_16_3,
ProtocolVersion.MINECRAFT_1_16_4,
+ ProtocolVersion.MINECRAFT_1_17,
ProtocolVersion.MINECRAFT_1_17_1,
+ ProtocolVersion.MINECRAFT_1_18,
+ //ProtocolVersion.MINECRAFT_1_18_1,
ProtocolVersion.MINECRAFT_1_18_2,
+ ProtocolVersion.MINECRAFT_1_19,
+ ProtocolVersion.MINECRAFT_1_19_1,
+ //ProtocolVersion.MINECRAFT_1_19_2,
+ ProtocolVersion.MINECRAFT_1_19_3,
ProtocolVersion.MINECRAFT_1_19_4,
- ProtocolVersion.MINECRAFT_1_20
+ ProtocolVersion.MINECRAFT_1_20,
+ ProtocolVersion.MINECRAFT_1_20_2
));
}
diff --git a/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java b/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java
index ba7f4fa..cc3ec88 100644
--- a/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java
+++ b/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java
@@ -38,6 +38,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.*;
public class ScoreboardManager {
+ private static final String NAMETAG_DELIMITER = ":::";
private PacketRegistration packetRegistration;
private final Velocitab plugin;
private final Set versions;
@@ -67,7 +68,7 @@ public class ScoreboardManager {
}
public void resetCache(@NotNull Player player) {
- String team = createdTeams.remove(player.getUniqueId());
+ final String team = createdTeams.remove(player.getUniqueId());
if (team != null) {
dispatchGroupPacket(UpdateTeamsPacket.removeTeam(plugin, team), player);
}
@@ -87,16 +88,15 @@ public class ScoreboardManager {
String suffix = split.length > 1 ? split[1] : "";
if (!createdTeams.getOrDefault(player.getUniqueId(), "").equals(role)) {
-
if (createdTeams.containsKey(player.getUniqueId())) {
dispatchGroupPacket(UpdateTeamsPacket.removeTeam(plugin, createdTeams.get(player.getUniqueId())), player);
}
createdTeams.put(player.getUniqueId(), role);
- this.nametags.put(role, prefix + ":::" + suffix);
+ this.nametags.put(role, prefix + NAMETAG_DELIMITER + 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);
+ } else if (!this.nametags.getOrDefault(role, "").equals(prefix + NAMETAG_DELIMITER + suffix)) {
+ this.nametags.put(role, prefix + NAMETAG_DELIMITER + suffix);
dispatchGroupPacket(UpdateTeamsPacket.changeNameTag(plugin, role, prefix, suffix), player);
}
}).exceptionally(e -> {
@@ -107,8 +107,7 @@ public class ScoreboardManager {
public void resendAllNameTags(Player player) {
-
- if (!plugin.getSettings().areNametagsEnabled()) {
+ if (!plugin.getSettings().doNametags()) {
return;
}
@@ -117,12 +116,12 @@ public class ScoreboardManager {
return;
}
- RegisteredServer serverInfo = optionalServerConnection.get().getServer();
-
- List siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName());
-
- List players = siblings.stream().map(RegisteredServer::getPlayersConnected).flatMap(Collection::stream).toList();
-
+ final RegisteredServer serverInfo = optionalServerConnection.get().getServer();
+ final List siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName());
+ final List players = siblings.stream()
+ .map(RegisteredServer::getPlayersConnected)
+ .flatMap(Collection::stream)
+ .toList();
players.forEach(p -> {
if (p == player || !p.isActive()) {
return;
@@ -138,10 +137,9 @@ public class ScoreboardManager {
return;
}
- String[] split = nametag.split(":::", 2);
- String prefix = split[0];
- String suffix = split.length > 1 ? split[1] : "";
-
+ final String[] split = nametag.split(NAMETAG_DELIMITER, 2);
+ final String prefix = split[0];
+ final String suffix = split.length > 1 ? split[1] : "";
dispatchPacket(UpdateTeamsPacket.create(plugin, role, "", prefix, suffix, p.getUsername()), player);
});
}
@@ -155,39 +153,35 @@ public class ScoreboardManager {
try {
final ConnectedPlayer connectedPlayer = (ConnectedPlayer) player;
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);
+ } catch (Throwable e) {
+ plugin.log(Level.ERROR, "Failed to dispatch packet (unsupported client or server version)", e);
}
}
private void dispatchGroupPacket(@NotNull UpdateTeamsPacket packet, @NotNull Player player) {
- Optional optionalServerConnection = player.getCurrentServer();
-
+ final Optional optionalServerConnection = player.getCurrentServer();
if (optionalServerConnection.isEmpty()) {
return;
}
- RegisteredServer serverInfo = optionalServerConnection.get().getServer();
+ final RegisteredServer serverInfo = optionalServerConnection.get().getServer();
+ final List siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName());
+ siblings.forEach(server -> server.getPlayersConnected().forEach(connected -> {
+ try {
- List siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName());
-
- siblings.forEach(s -> {
- s.getPlayersConnected().forEach(p -> {
-
- boolean canSee = !plugin.getVanishManager().isVanished(p.getUsername()) || plugin.getVanishManager().canSee(player.getUsername(), player.getUsername());
+ boolean canSee = !plugin.getVanishManager().isVanished(p.getUsername())
+ || plugin.getVanishManager().canSee(player.getUsername(), player.getUsername());
if (!canSee) {
return;
}
- 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);
- }
- });
- });
+ final ConnectedPlayer connectedPlayer = (ConnectedPlayer) connected;
+ connectedPlayer.getConnection().write(packet);
+ } catch (Throwable e) {
+ plugin.log(Level.ERROR, "Failed to dispatch packet (unsupported client or server version)", e);
+ }
+ }));
}
public void registerPacket() {
@@ -204,7 +198,8 @@ public class ScoreboardManager {
.mapping(0x55, MINECRAFT_1_17, true)
.mapping(0x58, MINECRAFT_1_19_1, true)
.mapping(0x56, MINECRAFT_1_19_3, true)
- .mapping(0x5A, MINECRAFT_1_19_4, true);
+ .mapping(0x5A, MINECRAFT_1_19_4, true)
+ .mapping(0x5C, MINECRAFT_1_20_2, true);
packetRegistration.register();
} catch (Throwable e) {
plugin.log(Level.ERROR, "Failed to register UpdateTeamsPacket", e);
diff --git a/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java b/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java
index f801b44..1097dda 100644
--- a/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java
+++ b/src/main/java/net/william278/velocitab/packet/UpdateTeamsPacket.java
@@ -30,7 +30,6 @@ 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;
@@ -62,7 +61,9 @@ public class UpdateTeamsPacket implements MinecraftPacket {
}
@NotNull
- protected static UpdateTeamsPacket create(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String displayName, @Nullable String prefix, @Nullable String suffix, @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)
@@ -77,7 +78,8 @@ public class UpdateTeamsPacket implements MinecraftPacket {
}
@NotNull
- protected static UpdateTeamsPacket changeNameTag(@NotNull Velocitab plugin, @NotNull String teamName, @Nullable String prefix, @Nullable String suffix) {
+ 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)
@@ -91,7 +93,8 @@ public class UpdateTeamsPacket implements MinecraftPacket {
}
@NotNull
- protected static UpdateTeamsPacket addToTeam(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String... teamMembers) {
+ protected static UpdateTeamsPacket addToTeam(@NotNull Velocitab plugin, @NotNull String teamName,
+ @NotNull String... teamMembers) {
return new UpdateTeamsPacket(plugin)
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
.mode(UpdateMode.ADD_PLAYERS)
@@ -99,7 +102,8 @@ public class UpdateTeamsPacket implements MinecraftPacket {
}
@NotNull
- protected static UpdateTeamsPacket removeFromTeam(@NotNull Velocitab plugin, @NotNull String teamName, @NotNull String... teamMembers) {
+ protected static UpdateTeamsPacket removeFromTeam(@NotNull Velocitab plugin, @NotNull String teamName,
+ @NotNull String... teamMembers) {
return new UpdateTeamsPacket(plugin)
.teamName(teamName.length() > 16 ? teamName.substring(0, 16) : teamName)
.mode(UpdateMode.REMOVE_PLAYERS)
@@ -117,13 +121,12 @@ public class UpdateTeamsPacket implements MinecraftPacket {
if (text == null) {
return 15;
}
- int intvar = text.lastIndexOf("ยง");
-
- if (intvar == -1 || intvar == text.length() - 1) {
+ int lastFormatIndex = text.lastIndexOf("ยง");
+ if (lastFormatIndex == -1 || lastFormatIndex == text.length() - 1) {
return 15;
}
- String last = text.substring(intvar, intvar + 2);
+ final String last = text.substring(lastFormatIndex, lastFormatIndex + 2);
return TeamColor.getColorId(last.charAt(1));
}
@@ -155,12 +158,15 @@ public class UpdateTeamsPacket implements MinecraftPacket {
private final int id;
TeamColor(char colorChar, int id) {
- this.colorChar= colorChar;
+ 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);
+ return Arrays.stream(values())
+ .filter(color -> color.colorChar == var)
+ .map(c -> c.id).findFirst()
+ .orElse(15);
}
}
@@ -176,7 +182,6 @@ public class UpdateTeamsPacket implements MinecraftPacket {
if (optionalManager.isEmpty()) {
return;
}
-
optionalManager.get().getPacketAdapter(protocolVersion).encode(byteBuf, this);
}
@@ -202,6 +207,7 @@ public class UpdateTeamsPacket implements MinecraftPacket {
return id;
}
+ @Nullable
public static UpdateMode byId(byte id) {
return Arrays.stream(values())
.filter(mode -> mode.id == id)
diff --git a/src/main/java/net/william278/velocitab/player/Role.java b/src/main/java/net/william278/velocitab/player/Role.java
index 8cbacd2..dde0d2b 100644
--- a/src/main/java/net/william278/velocitab/player/Role.java
+++ b/src/main/java/net/william278/velocitab/player/Role.java
@@ -23,7 +23,10 @@ import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
+import java.util.stream.Collectors;
public class Role implements Comparable {
public static final int DEFAULT_WEIGHT = 0;
@@ -49,7 +52,7 @@ public class Role implements Comparable {
@Override
public int compareTo(@NotNull Role o) {
- return weight - o.weight;
+ return Double.compare(weight, o.weight);
}
public Optional getName() {
@@ -69,8 +72,30 @@ public class Role implements Comparable {
}
@NotNull
- protected String getWeightString(int highestWeight) {
- return String.format("%0" + Integer.toString(highestWeight).length() + "d", highestWeight - weight);
+ protected String getWeightString() {
+ return compressNumber(Integer.MAX_VALUE / 4d - weight);
+ }
+
+ public String compressNumber(double number) {
+ int wholePart = (int) number;
+
+ final char decimalChar = (char) ((number - wholePart) * Character.MAX_VALUE);
+
+ final List charList = new ArrayList<>();
+
+ while (wholePart > 0) {
+ char digit = (char) (wholePart % Character.MAX_VALUE);
+
+ charList.add(0, digit);
+
+ wholePart /= Character.MAX_VALUE;
+ }
+
+ if (charList.isEmpty()) {
+ charList.add((char) 0);
+ }
+
+ return charList.stream().map(String::valueOf).collect(Collectors.joining()) + decimalChar;
}
}
diff --git a/src/main/java/net/william278/velocitab/player/TabPlayer.java b/src/main/java/net/william278/velocitab/player/TabPlayer.java
index cd51251..31d3eee 100644
--- a/src/main/java/net/william278/velocitab/player/TabPlayer.java
+++ b/src/main/java/net/william278/velocitab/player/TabPlayer.java
@@ -28,15 +28,12 @@ import net.william278.velocitab.tab.PlayerTabList;
import org.jetbrains.annotations.NotNull;
import org.slf4j.event.Level;
-import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
-import java.util.function.BiFunction;
public final class TabPlayer implements Comparable {
private final Player player;
private final Role role;
- private final int highestWeight;
@Getter
private int headerIndex = 0;
@Getter
@@ -45,10 +42,9 @@ public final class TabPlayer implements Comparable {
private Component lastDisplayname;
private String teamName;
- public TabPlayer(@NotNull Player player, @NotNull Role role, int highestWeight) {
+ public TabPlayer(@NotNull Player player, @NotNull Role role) {
this.player = player;
this.role = role;
- this.highestWeight = highestWeight;
}
@NotNull
@@ -61,6 +57,11 @@ public final class TabPlayer implements Comparable {
return role;
}
+ @NotNull
+ public String getRoleWeightString() {
+ return getRole().getWeightString();
+ }
+
/**
* Get the server name the player is currently on.
* Isn't affected by server aliases defined in the config.
@@ -125,13 +126,17 @@ public final class TabPlayer implements Comparable {
@NotNull
public CompletableFuture getTeamName(@NotNull Velocitab plugin) {
- return plugin.getSortingManager().map(sortingManager -> sortingManager.getTeamName(this))
- .orElseGet(() -> CompletableFuture.completedFuture(""))
- .thenApply(teamName -> {
- this.teamName = teamName;
- return teamName;
- }).exceptionally(e -> {
- plugin.log(Level.ERROR, "Failed to get team name for " + player.getUsername(), e);
+ if (!plugin.getSettings().isSortPlayers()) {
+ return CompletableFuture.completedFuture("");
+ }
+
+ final String sortingFormat = String.join("", plugin.getSettings().getSortingElements());
+ return Placeholder.replace(sortingFormat, plugin, this) // Replace placeholders
+ .thenApply(formatted -> formatted.length() > 12 ? formatted.substring(0, 12) : formatted) // Truncate
+ .thenApply(truncated -> truncated + getPlayer().getUniqueId().toString().substring(0, 4)) // Make unique
+ .thenApply(teamName -> this.teamName = teamName)
+ .exceptionally(e -> {
+ plugin.log(Level.ERROR, "Failed to get team name for " + player.getUsername(), e);
return "";
});
}
@@ -174,39 +179,4 @@ public final class TabPlayer implements Comparable {
return obj instanceof TabPlayer other && player.getUniqueId().equals(other.player.getUniqueId());
}
- /**
- * Elements for sorting players
- */
- @SuppressWarnings("unused")
- public enum SortableElement {
- ROLE_WEIGHT((player, plugin) -> player.getRole().getWeightString(player.highestWeight)),
- ROLE_NAME((player, plugin) -> player.getRole().getName()
- .map(name -> name.length() > 3 ? name.substring(0, 3) : name)
- .orElse("")),
- SERVER_NAME((player, plugin) -> player.getServerName()),
- SERVER_GROUP((player, plugin) -> {
- int orderSize = plugin.getSettings().getServerGroups().size();
- int position = player.getServerGroupPosition(plugin);
- return position >= 0
- ? String.format("%0" + Integer.toString(orderSize).length() + "d", position)
- : String.valueOf(orderSize);
- }),
- SERVER_GROUP_NAME(TabPlayer::getServerGroup);
-
- private final BiFunction elementResolver;
-
- SortableElement(@NotNull BiFunction elementResolver) {
- this.elementResolver = elementResolver;
- }
-
- @NotNull
- private String resolve(@NotNull TabPlayer tabPlayer, @NotNull Velocitab plugin) {
- return elementResolver.apply(tabPlayer, plugin);
- }
-
- public static Optional parse(@NotNull String s) {
- return Arrays.stream(values()).filter(element -> element.name().equalsIgnoreCase(s)).findFirst();
- }
- }
-
}
diff --git a/src/main/java/net/william278/velocitab/sorting/SortingManager.java b/src/main/java/net/william278/velocitab/sorting/SortingManager.java
deleted file mode 100644
index 324939e..0000000
--- a/src/main/java/net/william278/velocitab/sorting/SortingManager.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * This file is part of Velocitab, licensed under the Apache License 2.0.
- *
- * Copyright (c) William278
- * 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.sorting;
-
-import com.google.common.base.Strings;
-import net.william278.velocitab.Velocitab;
-import net.william278.velocitab.config.Placeholder;
-import net.william278.velocitab.player.TabPlayer;
-import org.slf4j.event.Level;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-public class SortingManager {
-
- private final Velocitab plugin;
- private static final String DELIMITER = ":::";
-
- public SortingManager(Velocitab plugin) {
- this.plugin = plugin;
- }
-
- public CompletableFuture getTeamName(TabPlayer player) {
- return Placeholder.replace(String.join(DELIMITER, plugin.getSettings().getSortingElements()), plugin, player)
- .thenApply(s -> Arrays.asList(s.split(DELIMITER)))
- .thenApply(v -> v.stream().map(this::adaptValue).collect(Collectors.toList()))
- .thenApply(v -> handleList(player, v));
- }
-
- private String handleList(TabPlayer player, List values) {
- String result = String.join("", values);
-
- if (result.length() > 12) {
- result = result.substring(0, 12);
- plugin.log(Level.WARN, "Sorting element list is too long, truncating to 16 characters");
- }
-
- result += player.getPlayer().getUniqueId().toString().substring(0, 4);
-
- return result;
- }
-
- private String adaptValue(String value) {
- if (value.isEmpty()) {
- return "";
- }
- if (value.matches("[0-9]+")) {
- int integer = Integer.parseInt(value);
- int intSortSize = 3;
- return (integer >= 0 ? 0 : 1) + String.format("%0" + intSortSize + "d", Integer.parseInt(Strings.repeat("9", intSortSize)) - Math.abs(integer));
- }
-
- if (value.length() > 6) {
- return value.substring(0, 4);
- }
-
- return value;
- }
-}
diff --git a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java
index 090dc7a..c92cf43 100644
--- a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java
+++ b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java
@@ -42,6 +42,9 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
+/**
+ * The main class for tracking the server TAB list
+ */
public class PlayerTabList {
private final Velocitab plugin;
private final ConcurrentLinkedQueue players;
@@ -68,19 +71,21 @@ public class PlayerTabList {
// Remove the player from the tracking list if they are switching servers
final RegisteredServer previousServer = event.getPreviousServer();
- if (previousServer == null) {
+ if (previousServer != null) {
players.removeIf(player -> player.getPlayer().getUniqueId().equals(joined.getUniqueId()));
}
// Get the servers in the group from the joined server name
// If the server is not in a group, use fallback
- Optional> serversInGroup = getGroupNames(joined.getCurrentServer()
+ final Optional> serversInGroup = getGroupNames(joined.getCurrentServer()
.map(ServerConnection::getServerInfo)
.map(ServerInfo::getName)
.orElse("?"));
+
// If the server is not in a group, use fallback.
- // If fallback is disabled, permit the player to switch excluded servers without header or footer override
- if (serversInGroup.isEmpty() && (previousServer != null && !this.fallbackServers.contains(previousServer.getServerInfo().getName()))) {
+ // If fallback is disabled, permit the player to switch excluded servers without a header or footer override
+ if (serversInGroup.isEmpty() &&
+ (previousServer != null && !this.fallbackServers.contains(previousServer.getServerInfo().getName()))) {
event.getPlayer().sendPlayerListHeaderAndFooter(Component.empty(), Component.empty());
return;
}
@@ -128,8 +133,7 @@ public class PlayerTabList {
plugin.getScoreboardManager().ifPresent(s -> {
s.resendAllNameTags(joined);
- plugin.getTabPlayer(joined).getTeamName(plugin)
- .thenAccept(t -> s.updateRole(joined, t));
+ plugin.getTabPlayer(joined).getTeamName(plugin).thenAccept(t -> s.updateRole(joined, t));
});
})
.delay(500, TimeUnit.MILLISECONDS)
@@ -164,20 +168,24 @@ public class PlayerTabList {
@Subscribe
public void onPlayerQuit(@NotNull DisconnectEvent event) {
- if (event.getLoginStatus() != DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN) return;
+ if (event.getLoginStatus() != DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN) {
+ return;
+ }
// Remove the player from the tracking list, Print warning if player was not removed
- if (!players.removeIf(player -> player.getPlayer().getUniqueId().equals(event.getPlayer().getUniqueId()))) {
- plugin.log("Failed to remove disconnecting player " + event.getPlayer().getUsername() + " (UUID: " + event.getPlayer().getUniqueId() + ")");
+ final UUID uuid = event.getPlayer().getUniqueId();
+ if (!players.removeIf(listed -> listed.getPlayer().getUniqueId().equals(uuid))) {
+ plugin.log(String.format("Failed to remove disconnecting player %s (UUID: %s)",
+ event.getPlayer().getUsername(), uuid.toString()));
}
// Remove the player from the tab list of all other players
- plugin.getServer().getAllPlayers().forEach(player -> player.getTabList().removeEntry(event.getPlayer().getUniqueId()));
+ plugin.getServer().getAllPlayers().forEach(player -> player.getTabList().removeEntry(uuid));
// Update the tab list of all players
plugin.getServer().getScheduler()
.buildTask(plugin, () -> players.forEach(player -> {
- player.getPlayer().getTabList().removeEntry(event.getPlayer().getUniqueId());
+ player.getPlayer().getTabList().removeEntry(uuid);
player.sendHeaderAndFooter(this);
}))
.delay(500, TimeUnit.MILLISECONDS)
@@ -201,19 +209,21 @@ public class PlayerTabList {
}
tabPlayer.getTeamName(plugin).thenAccept(teamName -> {
- if (teamName == null) return;
-
+ if (teamName.isBlank()) {
+ return;
+ }
plugin.getScoreboardManager().ifPresent(manager -> manager.updateRole(
- tabPlayer.getPlayer(),
- teamName
+ tabPlayer.getPlayer(), teamName
));
});
}
public void updatePlayerDisplayName(TabPlayer tabPlayer) {
- Component lastDisplayName = tabPlayer.getLastDisplayname();
+ final Component lastDisplayName = tabPlayer.getLastDisplayname();
tabPlayer.getDisplayName(plugin).thenAccept(displayName -> {
- if (displayName == null || displayName.equals(lastDisplayName)) return;
+ if (displayName == null || displayName.equals(lastDisplayName)) {
+ return;
+ }
boolean isVanished = plugin.getVanishManager().isVanished(tabPlayer.getPlayer().getUsername());
@@ -233,10 +243,12 @@ public class PlayerTabList {
});
}
+ // Update the display names of all listed players
public void updateDisplayNames() {
players.forEach(this::updatePlayerDisplayName);
}
+ // Get the component for the TAB list header
public CompletableFuture getHeader(@NotNull TabPlayer player) {
final String header = plugin.getSettings().getHeader(player.getServerGroup(plugin), player.getHeaderIndex());
player.incrementHeaderIndex(plugin);
@@ -245,6 +257,7 @@ public class PlayerTabList {
.thenApply(replaced -> plugin.getFormatter().format(replaced, player, plugin));
}
+ // Get the component for the TAB list footer
public CompletableFuture getFooter(@NotNull TabPlayer player) {
final String footer = plugin.getSettings().getFooter(player.getServerGroup(plugin), player.getFooterIndex());
player.incrementFooterIndex(plugin);