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
This commit is contained in:
William 2023-10-11 17:10:29 +01:00 committed by GitHub
parent fd17560f2e
commit 1f1e69ebca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 152 additions and 149 deletions

View File

@ -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

View File

@ -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<TabPlayer> getTabPlayer(String name) {
return server.getPlayer(name).map(this::getTabPlayer);
}

View File

@ -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);
}
}

View File

@ -39,129 +39,127 @@ import java.util.function.Supplier;
// Based on VPacketEvents PacketRegistration API
public final class PacketRegistration<P extends MinecraftPacket> {
private final Class<P> packetClass;
private Supplier<P> packetSupplier;
private ProtocolUtils.Direction direction;
private StateRegistry stateRegistry;
private final List<StateRegistry.PacketMapping> mappings = new ArrayList<>();
private final Class<P> packetClass;
private Supplier<P> packetSupplier;
private ProtocolUtils.Direction direction;
private StateRegistry stateRegistry;
private final List<StateRegistry.PacketMapping> mappings = new ArrayList<>();
public PacketRegistration<P> packetSupplier(final @NotNull Supplier<P> packetSupplier) {
this.packetSupplier = packetSupplier;
return this;
public PacketRegistration<P> packetSupplier(final @NotNull Supplier<P> packetSupplier) {
this.packetSupplier = packetSupplier;
return this;
}
public PacketRegistration<P> direction(final ProtocolUtils.Direction direction) {
this.direction = direction;
return this;
}
public PacketRegistration<P> stateRegistry(final @NotNull StateRegistry stateRegistry) {
this.stateRegistry = stateRegistry;
return this;
}
public PacketRegistration<P> 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<P> 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<P> 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<ProtocolVersion, StateRegistry.PacketRegistry.ProtocolRegistry> versions = (Map<ProtocolVersion, StateRegistry.PacketRegistry.ProtocolRegistry>) PACKET_REGISTRY$versions.invoke(packetRegistry);
versions.forEach((protocolVersion, protocolRegistry) -> {
try {
IntObjectMap<Supplier<?>> packetIdToSupplier = (IntObjectMap<Supplier<?>>) PACKET_REGISTRY$packetIdToSupplier.invoke(protocolRegistry);
Object2IntMap<Class<?>> packetClassToId = (Object2IntMap<Class<?>>) 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<P> 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 <P extends MinecraftPacket> PacketRegistration<P> of(Class<P> packetClass) {
return new PacketRegistration<>(packetClass);
}
private PacketRegistration(final @NotNull Class<P> 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<ProtocolVersion, StateRegistry.PacketRegistry.ProtocolRegistry> versions = (Map<ProtocolVersion, StateRegistry.PacketRegistry.ProtocolRegistry>) PACKET_REGISTRY$versions.invoke(packetRegistry);
versions.forEach((protocolVersion, protocolRegistry) -> {
try {
IntObjectMap<Supplier<?>> packetIdToSupplier = (IntObjectMap<Supplier<?>>) PACKET_REGISTRY$packetIdToSupplier.invoke(protocolRegistry);
Object2IntMap<Class<?>> packetClassToId = (Object2IntMap<Class<?>>) 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 <P extends MinecraftPacket> PacketRegistration<P> of(Class<P> packetClass) {
return new PacketRegistration<>(packetClass);
}
private PacketRegistration(final @NotNull Class<P> 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);
}
}
}

View File

@ -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
));
}

View File

@ -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<ServerConnection> optionalServerConnection = player.getCurrentServer();
final 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);
}
});
});
final RegisteredServer serverInfo = optionalServerConnection.get().getServer();
final List<RegisteredServer> 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);

View File

@ -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)