Implement native packets handling and remove Protocolize dependency (#44)

This commit is contained in:
Adrian 2023-04-19 04:31:37 -05:00 committed by GitHub
parent 4d586d28c3
commit d3d67cb613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 176 additions and 70 deletions

View File

@ -22,18 +22,17 @@ repositories {
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
maven { url = 'https://jitpack.io/' }
maven { url = 'https://repo.minebench.de/' }
maven { url = 'https://mvn.exceptionflug.de/repository/exceptionflug-public/' }
maven { url = "https://maven.elytrium.net/repo/" }
}
dependencies {
compileOnly 'com.velocitypowered:velocity-api:3.1.1'
compileOnly 'com.velocitypowered:velocity-api:3.2.0-SNAPSHOT'
compileOnly 'com.velocitypowered:velocity-proxy:3.2.0-SNAPSHOT'
compileOnly 'net.luckperms:api:5.4'
compileOnly 'dev.simplix:protocolize-api:2.2.6'
compileOnly 'io.netty:netty-codec-http:4.1.91.Final'
compileOnly 'io.github.miniplaceholders:miniplaceholders-api:2.0.0'
compileOnly 'net.william278:PAPIProxyBridge:1.2'
compileOnly 'org.projectlombok:lombok:1.18.26'
compileOnly 'net.kyori:adventure-text-minimessage:4.13.1'
implementation 'org.apache.commons:commons-text:1.10.0'
implementation 'net.william278:Annotaml:2.0.1'

View File

@ -132,10 +132,6 @@ public class Velocitab {
private void prepareScoreboardManager() {
if (settings.isSortPlayers()) {
if (!Hook.isPluginAvailable(this, "protocolize")) {
log("Protocolize is required to sort players by weight, but was not found. Disabling sorting.");
return;
}
this.scoreboardManager = new ScoreboardManager(this);
scoreboardManager.registerPacket();
}

View File

@ -92,7 +92,7 @@ public class Settings {
@Getter
@YamlKey("sort_players")
@YamlComment("Whether to sort players in the TAB list. Requires Protocolize to be installed.")
@YamlComment("Whether to sort players in the TAB list.")
private boolean sortPlayers = true;
@YamlKey("sort_players_by")

View File

@ -70,7 +70,7 @@ public abstract class Hook {
this.plugin = plugin;
}
public static boolean isPluginAvailable(@NotNull Velocitab plugin, @NotNull String id) {
private static boolean isPluginAvailable(@NotNull Velocitab plugin, @NotNull String id) {
return plugin.getServer().getPluginManager().getPlugin(id).isPresent();
}

View File

@ -0,0 +1,120 @@
/*
* This file is part of Velocitab, licensed under the Apache License 2.0.
*
* Copyright (c) William278 <will27528@gmail.com>
* 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.packet;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import org.jetbrains.annotations.NotNull;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
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<>();
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 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 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_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);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

View File

@ -20,16 +20,16 @@
package net.william278.velocitab.packet;
import com.velocitypowered.api.proxy.Player;
import dev.simplix.protocolize.api.PacketDirection;
import dev.simplix.protocolize.api.Protocol;
import dev.simplix.protocolize.api.Protocolize;
import dev.simplix.protocolize.api.player.ProtocolizePlayer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import net.william278.velocitab.Velocitab;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
import static com.velocitypowered.api.network.ProtocolVersion.*;
public class ScoreboardManager {
private final Velocitab plugin;
@ -85,13 +85,10 @@ public class ScoreboardManager {
plugin.getTabList().removeOfflinePlayer(player);
return;
}
try {
ProtocolizePlayer protocolizePlayer = Protocolize.playerProvider().player(player.getUniqueId());
if (protocolizePlayer != null) {
protocolizePlayer.sendPacket(packet);
} else {
plugin.log("Failed to get ProtocolizePlayer for player " + player.getUsername() + " (UUID: " + player.getUniqueId() + ")");
}
final ConnectedPlayer connectedPlayer = (ConnectedPlayer) player;
connectedPlayer.getConnection().write(packet);
} catch (Exception e) {
plugin.log("Failed to dispatch packet (is the client or server modded or using an illegal version?)", e);
}
@ -99,13 +96,19 @@ public class ScoreboardManager {
public void registerPacket() {
try {
Protocolize.protocolRegistration().registerPacket(
UpdateTeamsPacket.MAPPINGS,
Protocol.PLAY,
PacketDirection.CLIENTBOUND,
UpdateTeamsPacket.class
);
} catch (Exception e) {
PacketRegistration.of(UpdateTeamsPacket.class)
.direction(ProtocolUtils.Direction.CLIENTBOUND)
.packetSupplier(UpdateTeamsPacket::new)
.stateRegistry(StateRegistry.PLAY)
.mapping(0x47, MINECRAFT_1_13, false)
.mapping(0x4B, MINECRAFT_1_14, false)
.mapping(0x4C, MINECRAFT_1_15, false)
.mapping(0x55, MINECRAFT_1_17, false)
.mapping(0x58, MINECRAFT_1_19_1, false)
.mapping(0x56, MINECRAFT_1_19_3, false)
.mapping(0x5A, MINECRAFT_1_19_4, false)
.register();
} catch (Throwable e) {
plugin.log("Failed to register UpdateTeamsPacket", e);
}
}

View File

@ -19,11 +19,10 @@
package net.william278.velocitab.packet;
import dev.simplix.protocolize.api.PacketDirection;
import dev.simplix.protocolize.api.mapping.AbstractProtocolMapping;
import dev.simplix.protocolize.api.mapping.ProtocolIdMapping;
import dev.simplix.protocolize.api.packet.AbstractPacket;
import dev.simplix.protocolize.api.util.ProtocolUtil;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import lombok.*;
import lombok.experimental.Accessors;
@ -36,8 +35,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static dev.simplix.protocolize.api.util.ProtocolVersions.*;
@Getter
@Setter
@ToString
@ -45,17 +42,7 @@ import static dev.simplix.protocolize.api.util.ProtocolVersions.*;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(fluent = true)
public class UpdateTeamsPacket extends AbstractPacket {
protected static final List<ProtocolIdMapping> MAPPINGS = List.of(
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_13, MINECRAFT_1_13_2, 0x47),
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_14, MINECRAFT_1_14_4, 0x4B),
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_15, MINECRAFT_1_16_5, 0x4C),
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_17, MINECRAFT_1_19, 0x55),
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_19_1, MINECRAFT_1_19_2, 0x58),
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x56),
AbstractProtocolMapping.rangedIdMapping(MINECRAFT_1_19_4, MINECRAFT_LATEST, 0x5A)
);
public class UpdateTeamsPacket implements MinecraftPacket {
private String teamName;
private UpdateMode mode;
@ -99,58 +86,63 @@ public class UpdateTeamsPacket extends AbstractPacket {
.entities(Arrays.asList(teamMembers));
}
@NotNull
private static String getChatString(@NotNull String string) {
return "{\"text\":\"" + StringEscapeUtils.escapeJson(string) + "\"}";
}
@Override
public void read(ByteBuf byteBuf, PacketDirection packetDirection, int i) {
teamName = ProtocolUtil.readString(byteBuf);
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
teamName = ProtocolUtils.readString(byteBuf);
mode = UpdateMode.byId(byteBuf.readByte());
if (mode == UpdateMode.REMOVE_TEAM) {
return;
}
if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.UPDATE_INFO) {
displayName = ProtocolUtil.readString(byteBuf);
displayName = ProtocolUtils.readString(byteBuf);
friendlyFlags = FriendlyFlag.fromBitMask(byteBuf.readByte());
nameTagVisibility = NameTagVisibility.byId(ProtocolUtil.readString(byteBuf));
collisionRule = CollisionRule.byId(ProtocolUtil.readString(byteBuf));
nameTagVisibility = NameTagVisibility.byId(ProtocolUtils.readString(byteBuf));
collisionRule = CollisionRule.byId(ProtocolUtils.readString(byteBuf));
color = byteBuf.readByte();
prefix = ProtocolUtil.readString(byteBuf);
suffix = ProtocolUtil.readString(byteBuf);
prefix = ProtocolUtils.readString(byteBuf);
suffix = ProtocolUtils.readString(byteBuf);
}
if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.ADD_PLAYERS || mode == UpdateMode.REMOVE_PLAYERS) {
int entityCount = ProtocolUtil.readVarInt(byteBuf);
int entityCount = ProtocolUtils.readVarInt(byteBuf);
entities = new ArrayList<>(entityCount);
for (int j = 0; j < entityCount; j++) {
entities.add(ProtocolUtil.readString(byteBuf));
entities.add(ProtocolUtils.readString(byteBuf));
}
}
}
@Override
public void write(ByteBuf byteBuf, PacketDirection packetDirection, int i) {
ProtocolUtil.writeString(byteBuf, teamName);
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
ProtocolUtils.writeString(byteBuf, teamName);
byteBuf.writeByte(mode.id());
if (mode == UpdateMode.REMOVE_TEAM) {
return;
}
if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.UPDATE_INFO) {
ProtocolUtil.writeString(byteBuf, displayName);
ProtocolUtils.writeString(byteBuf, displayName);
byteBuf.writeByte(FriendlyFlag.toBitMask(friendlyFlags));
ProtocolUtil.writeString(byteBuf, nameTagVisibility.id());
ProtocolUtil.writeString(byteBuf, collisionRule.id());
ProtocolUtils.writeString(byteBuf, nameTagVisibility.id());
ProtocolUtils.writeString(byteBuf, collisionRule.id());
byteBuf.writeByte(color);
ProtocolUtil.writeString(byteBuf, prefix);
ProtocolUtil.writeString(byteBuf, suffix);
ProtocolUtils.writeString(byteBuf, prefix);
ProtocolUtils.writeString(byteBuf, suffix);
}
if (mode == UpdateMode.CREATE_TEAM || mode == UpdateMode.ADD_PLAYERS || mode == UpdateMode.REMOVE_PLAYERS) {
ProtocolUtil.writeVarInt(byteBuf, entities != null ? entities.size() : 0);
ProtocolUtils.writeVarInt(byteBuf, entities != null ? entities.size() : 0);
for (String entity : entities != null ? entities : new ArrayList<String>()) {
ProtocolUtil.writeString(byteBuf, entity);
ProtocolUtils.writeString(byteBuf, entity);
}
}
}
@NotNull
private static String getChatString(@NotNull String string) {
return "{\"text\":\"" + StringEscapeUtils.escapeJson(string) + "\"}";
@Override
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
return false;
}
public enum UpdateMode {

View File

@ -8,10 +8,6 @@
"William278"
],
"dependencies": [
{
"id": "protocolize",
"optional": true
},
{
"id": "luckperms",
"optional": true