From 1f1e69ebca01595e93797cd4331a03b1d2cd5129 Mon Sep 17 00:00:00 2001 From: William Date: Wed, 11 Oct 2023 17:10:29 +0100 Subject: [PATCH] Add support for Minecraft 1.20.2 (#99) * Add protocol mappings for 1.20.2 * Cleanup some exception handling * ci: Mark 1.20.2 as supported * Minor code formatting tweaks --- .github/workflows/java_ci.yml | 2 +- .../net/william278/velocitab/Velocitab.java | 2 +- .../net/william278/velocitab/hook/Hook.java | 6 +- .../velocitab/packet/PacketRegistration.java | 230 +++++++++--------- .../velocitab/packet/Protocol403Adapter.java | 3 +- .../velocitab/packet/ScoreboardManager.java | 38 ++- .../velocitab/packet/UpdateTeamsPacket.java | 20 +- 7 files changed, 152 insertions(+), 149 deletions(-) diff --git a/.github/workflows/java_ci.yml b/.github/workflows/java_ci.yml index 4ba9bd6..32165fa 100644 --- a/.github/workflows/java_ci.yml +++ b/.github/workflows/java_ci.yml @@ -60,7 +60,7 @@ jobs: 1.17.1 1.18.2 1.19.4 - 1.20.1 + 1.20.2 java: 16 - name: Upload GitHub Artifact uses: actions/upload-artifact@v2 diff --git a/src/main/java/net/william278/velocitab/Velocitab.java b/src/main/java/net/william278/velocitab/Velocitab.java index 145233f..5ffb2d0 100644 --- a/src/main/java/net/william278/velocitab/Velocitab.java +++ b/src/main/java/net/william278/velocitab/Velocitab.java @@ -31,7 +31,6 @@ import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.scheduler.ScheduledTask; -import lombok.Getter; import net.william278.annotaml.Annotaml; import net.william278.desertwell.util.UpdateChecker; import net.william278.desertwell.util.Version; @@ -207,6 +206,7 @@ public class Velocitab { ); } + @SuppressWarnings("unused") public Optional getTabPlayer(String name) { return server.getPlayer(name).map(this::getTabPlayer); } diff --git a/src/main/java/net/william278/velocitab/hook/Hook.java b/src/main/java/net/william278/velocitab/hook/Hook.java index 25d73d4..fafcb01 100644 --- a/src/main/java/net/william278/velocitab/hook/Hook.java +++ b/src/main/java/net/william278/velocitab/hook/Hook.java @@ -35,7 +35,7 @@ public abstract class Hook { try { plugin.log("Successfully hooked into LuckPerms"); return Optional.of(new LuckPermsHook(plugin)); - } catch (Exception e) { + } catch (Throwable e) { plugin.log(Level.WARN, "LuckPerms hook was not loaded: " + e.getMessage(), e); } } @@ -46,7 +46,7 @@ public abstract class Hook { try { plugin.log("Successfully hooked into PAPIProxyBridge"); return Optional.of(new PAPIProxyBridgeHook(plugin)); - } catch (Exception e) { + } catch (Throwable e) { plugin.log(Level.WARN, "PAPIProxyBridge hook was not loaded: " + e.getMessage(), e); } } @@ -57,7 +57,7 @@ public abstract class Hook { try { plugin.log("Successfully hooked into MiniPlaceholders"); return Optional.of(new MiniPlaceholdersHook(plugin)); - } catch (Exception e) { + } catch (Throwable e) { plugin.log(Level.WARN, "MiniPlaceholders hook was not loaded: " + e.getMessage(), e); } } diff --git a/src/main/java/net/william278/velocitab/packet/PacketRegistration.java b/src/main/java/net/william278/velocitab/packet/PacketRegistration.java index b37ffa3..d0e7e35 100644 --- a/src/main/java/net/william278/velocitab/packet/PacketRegistration.java +++ b/src/main/java/net/william278/velocitab/packet/PacketRegistration.java @@ -39,129 +39,127 @@ import java.util.function.Supplier; // Based on VPacketEvents PacketRegistration API public final class PacketRegistration

{ - private final Class

packetClass; - private Supplier

packetSupplier; - private ProtocolUtils.Direction direction; - private StateRegistry stateRegistry; - private final List mappings = new ArrayList<>(); + private final Class

packetClass; + private Supplier

packetSupplier; + private ProtocolUtils.Direction direction; + private StateRegistry stateRegistry; + private final List 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..5ce589e 100644 --- a/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java +++ b/src/main/java/net/william278/velocitab/packet/Protocol403Adapter.java @@ -43,7 +43,8 @@ public class Protocol403Adapter extends TeamsPacketAdapter { ProtocolVersion.MINECRAFT_1_17_1, ProtocolVersion.MINECRAFT_1_18_2, 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 9fcafa5..f2a7fcd 100644 --- a/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java +++ b/src/main/java/net/william278/velocitab/packet/ScoreboardManager.java @@ -95,8 +95,8 @@ public class ScoreboardManager { createdTeams.put(player.getUniqueId(), 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); + } 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 -> { @@ -108,7 +108,7 @@ public class ScoreboardManager { public void resendAllNameTags(Player player) { - if(!plugin.getSettings().areNametagsEnabled()) { + if (!plugin.getSettings().areNametagsEnabled()) { return; } @@ -155,32 +155,27 @@ public class ScoreboardManager { try { final ConnectedPlayer connectedPlayer = (ConnectedPlayer) player; connectedPlayer.getConnection().write(packet); - } catch (Exception e) { + } catch (Throwable e) { plugin.log(Level.ERROR, "Failed to dispatch packet (is the client or server modded or using an illegal 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(); - - List 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); - } - }); - }); + final RegisteredServer serverInfo = optionalServerConnection.get().getServer(); + final List siblings = plugin.getTabList().getGroupServers(serverInfo.getServerInfo().getName()); + siblings.forEach(server -> server.getPlayersConnected().forEach(connected -> { + try { + 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() { @@ -197,7 +192,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..249f871 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) @@ -160,7 +164,10 @@ public class UpdateTeamsPacket implements MinecraftPacket { } 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); } } @@ -202,6 +209,7 @@ public class UpdateTeamsPacket implements MinecraftPacket { return id; } + @Nullable public static UpdateMode byId(byte id) { return Arrays.stream(values()) .filter(mode -> mode.id == id)