feat: add support for 1.20.5
This commit is contained in:
parent
f822c8523c
commit
8d48e74f49
|
@ -33,7 +33,8 @@ final class ChannelProtocolUtil {
|
||||||
|
|
||||||
BiFunction<Channel, PacketType.Sender, Object> baseResolver = null;
|
BiFunction<Channel, PacketType.Sender, Object> baseResolver = null;
|
||||||
if (attributeKeys.isEmpty()) {
|
if (attributeKeys.isEmpty()) {
|
||||||
baseResolver = new Post1_20_4WrappedResolver();
|
// since 1.20.5 the protocol is stored as final field in de-/encoder
|
||||||
|
baseResolver = new Post1_20_5WrappedResolver();
|
||||||
} else if (attributeKeys.size() == 1) {
|
} else if (attributeKeys.size() == 1) {
|
||||||
// if there is only one attribute key we can assume it's the correct one (1.8 - 1.20.1)
|
// if there is only one attribute key we can assume it's the correct one (1.8 - 1.20.1)
|
||||||
Object protocolKey = Accessors.getFieldAccessor(attributeKeys.get(0)).get(null);
|
Object protocolKey = Accessors.getFieldAccessor(attributeKeys.get(0)).get(null);
|
||||||
|
@ -137,7 +138,10 @@ final class ChannelProtocolUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Post1_20_4WrappedResolver implements BiFunction<Channel, PacketType.Sender, Object> {
|
/**
|
||||||
|
* Since 1.20.5 the protocol is stored as final field in de-/encoder
|
||||||
|
*/
|
||||||
|
private static final class Post1_20_5WrappedResolver implements BiFunction<Channel, PacketType.Sender, Object> {
|
||||||
|
|
||||||
// lazy initialized when needed
|
// lazy initialized when needed
|
||||||
private Function<Object, Object> serverProtocolAccessor;
|
private Function<Object, Object> serverProtocolAccessor;
|
||||||
|
@ -151,23 +155,11 @@ final class ChannelProtocolUtil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Function<Object, Object> protocolAccessor = this.getProtocolAccessor(sender, codecHandler.getClass());
|
Function<Object, Object> protocolAccessor = this.getProtocolAccessor(codecHandler.getClass(), sender);
|
||||||
|
|
||||||
return protocolAccessor.apply(codecHandler);
|
return protocolAccessor.apply(codecHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getKeyForSender(PacketType.Sender sender) {
|
private Function<Object, Object> getProtocolAccessor(Class<?> codecHandler, PacketType.Sender sender) {
|
||||||
switch (sender) {
|
|
||||||
case SERVER:
|
|
||||||
return "encoder";
|
|
||||||
case CLIENT:
|
|
||||||
return "decoder";
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Illegal packet sender " + sender.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Function<Object, Object> getProtocolAccessor(PacketType.Sender sender, Class<?> codecHandler) {
|
|
||||||
switch (sender) {
|
switch (sender) {
|
||||||
case SERVER:
|
case SERVER:
|
||||||
if (this.serverProtocolAccessor == null) {
|
if (this.serverProtocolAccessor == null) {
|
||||||
|
@ -184,17 +176,27 @@ final class ChannelProtocolUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<Object, Object> getProtocolAccessor(Class<?> codecHandler) {
|
private String getKeyForSender(PacketType.Sender sender) {
|
||||||
Class<?> protocolInfoClass = MinecraftReflection.getMinecraftClass("network.ProtocolInfo");
|
switch (sender) {
|
||||||
|
case SERVER:
|
||||||
|
return "encoder";
|
||||||
|
case CLIENT:
|
||||||
|
return "decoder";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Illegal packet sender " + sender.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MethodAccessor protocolAccessor = Accessors.getMethodAccessor(
|
private Function<Object, Object> getProtocolAccessor(Class<?> codecHandler) {
|
||||||
FuzzyReflection.fromClass(protocolInfoClass)
|
Class<?> protocolInfoClass = MinecraftReflection.getProtocolInfoClass();
|
||||||
.getMethod(FuzzyMethodContract.newBuilder()
|
|
||||||
.returnTypeExact(MinecraftReflection.getEnumProtocolClass())
|
MethodAccessor protocolAccessor = Accessors.getMethodAccessor(FuzzyReflection
|
||||||
.build()));
|
.fromClass(protocolInfoClass)
|
||||||
|
.getMethodByReturnTypeAndParameters("id", MinecraftReflection.getEnumProtocolClass(), new Class[0]));
|
||||||
|
|
||||||
FieldAccessor protocolInfoAccessor = Accessors.getFieldAccessor(codecHandler, protocolInfoClass, true);
|
FieldAccessor protocolInfoAccessor = Accessors.getFieldAccessor(codecHandler, protocolInfoClass, true);
|
||||||
|
|
||||||
|
// get ProtocolInfo from handler and get EnumProtocol of ProtocolInfo
|
||||||
return (handler) -> {
|
return (handler) -> {
|
||||||
Object protocolInfo = protocolInfoAccessor.get(handler);
|
Object protocolInfo = protocolInfoAccessor.get(handler);
|
||||||
return protocolAccessor.invoke(protocolInfo);
|
return protocolAccessor.invoke(protocolInfo);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.channel.EventLoop;
|
import io.netty.channel.EventLoop;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
|
@ -202,9 +203,18 @@ public class NettyChannelInjector implements Injector {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChannelPipeline pipeline = this.wrappedChannel.pipeline();
|
||||||
|
|
||||||
|
// since 1.20.5 the encoder is renamed to outbound_config only in the handshake phase
|
||||||
|
String encoderName = pipeline.get("outbound_config") != null
|
||||||
|
? "outbound_config" : "encoder";
|
||||||
|
|
||||||
// inject our handlers
|
// inject our handlers
|
||||||
this.wrappedChannel.pipeline().addAfter("encoder", WIRE_PACKET_ENCODER_NAME, WIRE_PACKET_ENCODER);
|
pipeline.addAfter(
|
||||||
this.wrappedChannel.pipeline().addAfter(
|
encoderName,
|
||||||
|
WIRE_PACKET_ENCODER_NAME,
|
||||||
|
WIRE_PACKET_ENCODER);
|
||||||
|
pipeline.addAfter(
|
||||||
"decoder",
|
"decoder",
|
||||||
INTERCEPTOR_NAME,
|
INTERCEPTOR_NAME,
|
||||||
new InboundPacketInterceptor(this, this.channelListener));
|
new InboundPacketInterceptor(this, this.channelListener));
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package com.comphenix.protocol.injector.packet;
|
package com.comphenix.protocol.injector.packet;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
@ -39,6 +38,9 @@ import com.comphenix.protocol.PacketType.Sender;
|
||||||
import com.comphenix.protocol.ProtocolLogger;
|
import com.comphenix.protocol.ProtocolLogger;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
|
||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||||
|
@ -47,6 +49,7 @@ import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static packet registry in Minecraft.
|
* Static packet registry in Minecraft.
|
||||||
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class PacketRegistry {
|
public class PacketRegistry {
|
||||||
|
@ -61,6 +64,7 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a register we are currently building.
|
* Represents a register we are currently building.
|
||||||
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
protected static class Register {
|
protected static class Register {
|
||||||
|
@ -74,7 +78,8 @@ public class PacketRegistry {
|
||||||
volatile Set<PacketType> clientPackets = new HashSet<>();
|
volatile Set<PacketType> clientPackets = new HashSet<>();
|
||||||
final List<MapContainer> containers = new ArrayList<>();
|
final List<MapContainer> containers = new ArrayList<>();
|
||||||
|
|
||||||
public Register() {}
|
public Register() {
|
||||||
|
}
|
||||||
|
|
||||||
public void registerPacket(PacketType type, Class<?> clazz, Sender sender) {
|
public void registerPacket(PacketType type, Class<?> clazz, Sender sender) {
|
||||||
typeToClass.put(type, Optional.of(clazz));
|
typeToClass.put(type, Optional.of(clazz));
|
||||||
|
@ -95,6 +100,7 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the current register is outdated.
|
* Determine if the current register is outdated.
|
||||||
|
*
|
||||||
* @return TRUE if it is, FALSE otherwise.
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isOutdated() {
|
public boolean isOutdated() {
|
||||||
|
@ -140,7 +146,8 @@ public class PacketRegistry {
|
||||||
modifier = new StructureModifier<>(protocol.getClass().getSuperclass());
|
modifier = new StructureModifier<>(protocol.getClass().getSuperclass());
|
||||||
}
|
}
|
||||||
|
|
||||||
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol)
|
||||||
|
.withType(Map.class);
|
||||||
for (Map.Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
|
for (Map.Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
|
||||||
String direction = entry.getKey().toString();
|
String direction = entry.getKey().toString();
|
||||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||||
|
@ -175,7 +182,7 @@ public class PacketRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static synchronized Register createNewRegister() {
|
private static synchronized Register createRegisterV1_15_0() {
|
||||||
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
|
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
|
||||||
|
|
||||||
// ID to Packet class maps
|
// ID to Packet class maps
|
||||||
|
@ -192,11 +199,8 @@ public class PacketRegistry {
|
||||||
for (Object protocol : protocols) {
|
for (Object protocol : protocols) {
|
||||||
if (mainMapField == null) {
|
if (mainMapField == null) {
|
||||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true);
|
FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true);
|
||||||
mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
|
mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder().banModifier(Modifier.STATIC)
|
||||||
.banModifier(Modifier.STATIC)
|
.requireModifier(Modifier.FINAL).typeDerivedOf(Map.class).build());
|
||||||
.requireModifier(Modifier.FINAL)
|
|
||||||
.typeDerivedOf(Map.class)
|
|
||||||
.build());
|
|
||||||
mainMapField.setAccessible(true);
|
mainMapField.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,28 +218,22 @@ public class PacketRegistry {
|
||||||
Class<?> packetHolderClass = holder.getClass();
|
Class<?> packetHolderClass = holder.getClass();
|
||||||
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
|
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
|
||||||
FuzzyReflection holderFuzzy = FuzzyReflection.fromClass(packetHolderClass, true);
|
FuzzyReflection holderFuzzy = FuzzyReflection.fromClass(packetHolderClass, true);
|
||||||
holderClassField = holderFuzzy.getField(FuzzyFieldContract.newBuilder()
|
holderClassField = holderFuzzy
|
||||||
.banModifier(Modifier.STATIC)
|
.getField(FuzzyFieldContract.newBuilder().banModifier(Modifier.STATIC)
|
||||||
.requireModifier(Modifier.FINAL)
|
.requireModifier(Modifier.FINAL)
|
||||||
.typeMatches(FuzzyClassContract.newBuilder()
|
.typeMatches(FuzzyClassContract.newBuilder().method(FuzzyMethodContract
|
||||||
.method(FuzzyMethodContract.newBuilder()
|
.newBuilder().returnTypeExact(MinecraftReflection.getPacketClass())
|
||||||
.returnTypeExact(MinecraftReflection.getPacketClass())
|
.parameterCount(2).parameterExactType(int.class, 0).parameterExactType(
|
||||||
.parameterCount(2)
|
MinecraftReflection.getPacketDataSerializerClass(), 1)
|
||||||
.parameterExactType(int.class, 0)
|
.build()).build())
|
||||||
.parameterExactType(MinecraftReflection.getPacketDataSerializerClass(), 1)
|
|
||||||
.build())
|
|
||||||
.build())
|
|
||||||
.build());
|
.build());
|
||||||
holderClassField.setAccessible(true);
|
holderClassField.setAccessible(true);
|
||||||
packetHolderClass = holderClassField.getType();
|
packetHolderClass = holderClassField.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(packetHolderClass, true);
|
FuzzyReflection fuzzy = FuzzyReflection.fromClass(packetHolderClass, true);
|
||||||
packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder()
|
packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder().banModifier(Modifier.STATIC)
|
||||||
.banModifier(Modifier.STATIC)
|
.requireModifier(Modifier.FINAL).typeDerivedOf(Map.class).build());
|
||||||
.requireModifier(Modifier.FINAL)
|
|
||||||
.typeDerivedOf(Map.class)
|
|
||||||
.build());
|
|
||||||
packetMapField.setAccessible(true);
|
packetMapField.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,13 +265,13 @@ public class PacketRegistry {
|
||||||
// Maps we have to occasionally check have changed
|
// Maps we have to occasionally check have changed
|
||||||
// TODO: Find equivalent in Object2IntMap
|
// TODO: Find equivalent in Object2IntMap
|
||||||
|
|
||||||
/* for (Object map : serverMaps.values()) {
|
/*
|
||||||
result.containers.add(new MapContainer(map));
|
* for (Object map : serverMaps.values()) { result.containers.add(new
|
||||||
}
|
* MapContainer(map)); }
|
||||||
|
*
|
||||||
for (Object map : clientMaps.values()) {
|
* for (Object map : clientMaps.values()) { result.containers.add(new
|
||||||
result.containers.add(new MapContainer(map));
|
* MapContainer(map)); }
|
||||||
} */
|
*/
|
||||||
|
|
||||||
for (Object protocol : protocols) {
|
for (Object protocol : protocols) {
|
||||||
Enum<?> enumProtocol = (Enum<?>) protocol;
|
Enum<?> enumProtocol = (Enum<?>) protocol;
|
||||||
|
@ -292,88 +290,37 @@ public class PacketRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static synchronized Register createNewNewRegister() {
|
private static synchronized Register createRegisterV1_20_5() {
|
||||||
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
|
Object[] protocols = ENUM_PROTOCOL.getEnumConstants();
|
||||||
|
|
||||||
// ID to Packet class maps
|
// PacketType<?> to class map
|
||||||
final Map<Object, Class<?>> packetTypeMap = new HashMap<>();
|
final Map<Object, Class<?>> packetTypeMap = new HashMap<>();
|
||||||
final Map<Object, Map<Class<?>, Integer>> serverMaps = new LinkedHashMap<>();
|
|
||||||
final Map<Object, Map<Class<?>, Integer>> clientMaps = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
String[] protocolClassNames = new String[] {
|
// List of all class containing PacketTypes
|
||||||
"configuration.ConfigurationProtocols",
|
String[] packetTypesClassNames = new String[] { "common.CommonPacketTypes",
|
||||||
"game.GameProtocols",
|
"configuration.ConfigurationPacketTypes", "cookie.CookiePacketTypes", "game.GamePacketTypes",
|
||||||
"handshake.HandshakeProtocols",
|
"handshake.HandshakePacketTypes", "login.LoginPacketTypes", "ping.PingPacketTypes",
|
||||||
"login.LoginProtocols",
|
"status.StatusPacketTypes", };
|
||||||
"status.StatusProtocols"
|
|
||||||
};
|
|
||||||
|
|
||||||
String[] packetTypesClassNames = new String[] {
|
|
||||||
"common.CommonPacketTypes",
|
|
||||||
"configuration.ConfigurationPacketTypes",
|
|
||||||
"cookie.CookiePacketTypes",
|
|
||||||
"game.GamePacketTypes",
|
|
||||||
"handshake.HandshakePacketTypes",
|
|
||||||
"login.LoginPacketTypes",
|
|
||||||
"ping.PingPacketTypes",
|
|
||||||
"status.StatusPacketTypes",
|
|
||||||
};
|
|
||||||
|
|
||||||
Class<?> protocolInfoClass = MinecraftReflection.getMinecraftClass("network.ProtocolInfo");
|
|
||||||
Class<?> protocolInfoUnboundClass = MinecraftReflection.getMinecraftClass("network.ProtocolInfo$a");
|
|
||||||
Class<?> streamCodecClass = MinecraftReflection.getMinecraftClass("network.codec.StreamCodec");
|
|
||||||
Class<?> idDispatchCodecClass = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec");
|
|
||||||
Class<?> packetTypeClass = MinecraftReflection.getMinecraftClass("network.protocol.PacketType");
|
Class<?> packetTypeClass = MinecraftReflection.getMinecraftClass("network.protocol.PacketType");
|
||||||
Class<?> protocolDirectionClass = MinecraftReflection.getMinecraftClass("network.protocol.EnumProtocolDirection");
|
|
||||||
|
|
||||||
Function<?, ?> emptyFunction = input -> null;
|
|
||||||
|
|
||||||
Method protocolMethod = FuzzyReflection.fromClass(protocolInfoClass)
|
|
||||||
.getMethod(FuzzyMethodContract.newBuilder()
|
|
||||||
.returnTypeExact(MinecraftReflection.getEnumProtocolClass())
|
|
||||||
.build());
|
|
||||||
protocolMethod.setAccessible(true);
|
|
||||||
|
|
||||||
Method directionMethod = FuzzyReflection.fromClass(protocolInfoClass)
|
|
||||||
.getMethod(FuzzyMethodContract.newBuilder()
|
|
||||||
.returnTypeExact(protocolDirectionClass)
|
|
||||||
.build());
|
|
||||||
directionMethod.setAccessible(true);
|
|
||||||
|
|
||||||
Method codecMethod = FuzzyReflection.fromClass(protocolInfoClass)
|
|
||||||
.getMethod(FuzzyMethodContract.newBuilder()
|
|
||||||
.returnTypeExact(streamCodecClass)
|
|
||||||
.build());
|
|
||||||
codecMethod.setAccessible(true);
|
|
||||||
|
|
||||||
Method bindMethod = FuzzyReflection.fromClass(protocolInfoUnboundClass)
|
|
||||||
.getMethod(FuzzyMethodContract.newBuilder()
|
|
||||||
.returnTypeExact(protocolInfoClass)
|
|
||||||
.build());
|
|
||||||
bindMethod.setAccessible(true);
|
|
||||||
|
|
||||||
Field toIdField = FuzzyReflection.fromClass(idDispatchCodecClass, true)
|
|
||||||
.getField(FuzzyFieldContract.newBuilder()
|
|
||||||
.typeDerivedOf(Map.class)
|
|
||||||
.build());
|
|
||||||
toIdField.setAccessible(true);
|
|
||||||
|
|
||||||
for (String packetTypesClassName : packetTypesClassNames) {
|
for (String packetTypesClassName : packetTypesClassNames) {
|
||||||
Class<?> packetTypesClass = MinecraftReflection.getMinecraftClass("network.protocol." + packetTypesClassName);
|
Class<?> packetTypesClass = MinecraftReflection
|
||||||
|
.getMinecraftClass("network.protocol." + packetTypesClassName);
|
||||||
|
|
||||||
|
// check every field for "static final PacketType<?>"
|
||||||
for (Field field : packetTypesClass.getDeclaredFields()) {
|
for (Field field : packetTypesClass.getDeclaredFields()) {
|
||||||
try {
|
try {
|
||||||
if (!Modifier.isFinal(field.getModifiers()) || !Modifier.isStatic(field.getModifiers())) {
|
if (!Modifier.isFinal(field.getModifiers()) || !Modifier.isStatic(field.getModifiers())) {
|
||||||
System.out.println("failed modifier " + field);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object packetType = field.get(null);
|
Object packetType = field.get(null);
|
||||||
if (!packetTypeClass.isInstance(packetType)) {
|
if (!packetTypeClass.isInstance(packetType)) {
|
||||||
System.out.println("failed packetTypeClass " + field);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retrieve the generic type T of the PacketType<T> field
|
||||||
Type packet = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
|
Type packet = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
|
||||||
if (packet instanceof Class<?>) {
|
if (packet instanceof Class<?>) {
|
||||||
packetTypeMap.put(packetType, (Class<?>) packet);
|
packetTypeMap.put(packetType, (Class<?>) packet);
|
||||||
|
@ -385,34 +332,72 @@ public class PacketRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ID to Packet class maps
|
||||||
|
final Map<Object, Map<Class<?>, Integer>> serverMaps = new LinkedHashMap<>();
|
||||||
|
final Map<Object, Map<Class<?>, Integer>> clientMaps = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// List of all class containing ProtocolInfos
|
||||||
|
String[] protocolClassNames = new String[] { "configuration.ConfigurationProtocols", "game.GameProtocols",
|
||||||
|
"handshake.HandshakeProtocols", "login.LoginProtocols", "status.StatusProtocols" };
|
||||||
|
|
||||||
|
Class<?> protocolInfoClass = MinecraftReflection.getProtocolInfoClass();
|
||||||
|
Class<?> protocolInfoUnboundClass = MinecraftReflection.getMinecraftClass("network.ProtocolInfo$a");
|
||||||
|
Class<?> streamCodecClass = MinecraftReflection.getMinecraftClass("network.codec.StreamCodec");
|
||||||
|
Class<?> idDispatchCodecClass = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec");
|
||||||
|
Class<?> protocolDirectionClass = MinecraftReflection
|
||||||
|
.getMinecraftClass("network.protocol.EnumProtocolDirection");
|
||||||
|
|
||||||
|
Function<?, ?> emptyFunction = input -> null;
|
||||||
|
|
||||||
|
FuzzyReflection protocolInfoReflection = FuzzyReflection.fromClass(protocolInfoClass);
|
||||||
|
|
||||||
|
MethodAccessor protocolAccessor = Accessors.getMethodAccessor(protocolInfoReflection
|
||||||
|
.getMethodByReturnTypeAndParameters("id", MinecraftReflection.getEnumProtocolClass(), new Class[0]));
|
||||||
|
|
||||||
|
MethodAccessor directionAccessor = Accessors.getMethodAccessor(protocolInfoReflection
|
||||||
|
.getMethodByReturnTypeAndParameters("flow", protocolDirectionClass, new Class[0]));
|
||||||
|
|
||||||
|
MethodAccessor codecAccessor = Accessors.getMethodAccessor(
|
||||||
|
protocolInfoReflection.getMethodByReturnTypeAndParameters("codec", streamCodecClass, new Class[0]));
|
||||||
|
|
||||||
|
MethodAccessor bindAccessor = Accessors.getMethodAccessor(FuzzyReflection.fromClass(protocolInfoUnboundClass)
|
||||||
|
.getMethodByReturnTypeAndParameters("bind", protocolInfoClass, new Class[] { Function.class }));
|
||||||
|
|
||||||
|
FieldAccessor toIdAccessor = Accessors.getFieldAccessor(FuzzyReflection.fromClass(idDispatchCodecClass, true)
|
||||||
|
.getField(FuzzyFieldContract.newBuilder().typeDerivedOf(Map.class).build()));
|
||||||
|
|
||||||
for (String protocolClassName : protocolClassNames) {
|
for (String protocolClassName : protocolClassNames) {
|
||||||
Class<?> protocolClass = MinecraftReflection.getMinecraftClass("network.protocol." + protocolClassName);
|
Class<?> protocolClass = MinecraftReflection.getMinecraftClass("network.protocol." + protocolClassName);
|
||||||
|
|
||||||
for (Field field : protocolClass.getDeclaredFields()) {
|
for (Field field : protocolClass.getDeclaredFields()) {
|
||||||
try {
|
try {
|
||||||
|
// ignore none static and final fields
|
||||||
if (!Modifier.isFinal(field.getModifiers()) || !Modifier.isStatic(field.getModifiers())) {
|
if (!Modifier.isFinal(field.getModifiers()) || !Modifier.isStatic(field.getModifiers())) {
|
||||||
System.out.println("failed modifier " + field);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object protocolInfo = field.get(null);
|
Object protocolInfo = field.get(null);
|
||||||
|
|
||||||
|
// bind unbound ProtocolInfo to empty function to get real ProtocolInfo
|
||||||
if (protocolInfoUnboundClass.isInstance(protocolInfo)) {
|
if (protocolInfoUnboundClass.isInstance(protocolInfo)) {
|
||||||
protocolInfo = bindMethod.invoke(protocolInfo, new Object[] { emptyFunction });
|
protocolInfo = bindAccessor.invoke(protocolInfo, new Object[] { emptyFunction });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore any field that isn't a ProtocolInfo
|
||||||
if (!protocolInfoClass.isInstance(protocolInfo)) {
|
if (!protocolInfoClass.isInstance(protocolInfo)) {
|
||||||
System.out.println("failed protocolInfoClass " + field);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object codec = codecMethod.invoke(protocolInfo);
|
// get codec and check if codec is instance of IdDispatchCodec
|
||||||
|
// since that is the only support codec as of now
|
||||||
|
Object codec = codecAccessor.invoke(protocolInfo);
|
||||||
if (!idDispatchCodecClass.isInstance(codec)) {
|
if (!idDispatchCodecClass.isInstance(codec)) {
|
||||||
System.out.println("failed idDispatchCodecClass " + field);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retrieve packetTypeMap and convert it to packetIdMap
|
||||||
Map<Class<?>, Integer> packetMap = new HashMap<>();
|
Map<Class<?>, Integer> packetMap = new HashMap<>();
|
||||||
Map<Object, Integer> packetTypeIdMap = (Map<Object, Integer>) toIdField.get(codec);
|
Map<Object, Integer> packetTypeIdMap = (Map<Object, Integer>) toIdAccessor.get(codec);
|
||||||
|
|
||||||
for (Map.Entry<Object, Integer> entry : packetTypeIdMap.entrySet()) {
|
for (Map.Entry<Object, Integer> entry : packetTypeIdMap.entrySet()) {
|
||||||
Class<?> packet = packetTypeMap.get(entry.getKey());
|
Class<?> packet = packetTypeMap.get(entry.getKey());
|
||||||
|
@ -423,9 +408,9 @@ public class PacketRegistry {
|
||||||
packetMap.put(packet, entry.getValue());
|
packetMap.put(packet, entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get EnumProtocol and Direction of protocol info
|
||||||
Object protocol = protocolMethod.invoke(protocolInfo);
|
Object protocol = protocolAccessor.invoke(protocolInfo);
|
||||||
String direction = directionMethod.invoke(protocolInfo).toString();
|
String direction = directionAccessor.invoke(protocolInfo).toString();
|
||||||
|
|
||||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||||
serverMaps.put(protocol, packetMap);
|
serverMaps.put(protocol, packetMap);
|
||||||
|
@ -458,8 +443,8 @@ public class PacketRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverses a key->value map to value->key
|
* Reverses a key->value map to value->key Non-deterministic behavior when
|
||||||
* Non-deterministic behavior when multiple keys are mapped to the same value
|
* multiple keys are mapped to the same value
|
||||||
*/
|
*/
|
||||||
private static <K, V> Map<V, K> reverse(Map<K, V> map) {
|
private static <K, V> Map<V, K> reverse(Map<K, V> map) {
|
||||||
Map<V, K> newMap = new HashMap<>(map.size());
|
Map<V, K> newMap = new HashMap<>(map.size());
|
||||||
|
@ -469,7 +454,8 @@ public class PacketRegistry {
|
||||||
return newMap;
|
return newMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void associatePackets(Register register, Map<Integer, Class<?>> lookup, PacketType.Protocol protocol, Sender sender) {
|
protected static void associatePackets(Register register, Map<Integer, Class<?>> lookup,
|
||||||
|
PacketType.Protocol protocol, Sender sender) {
|
||||||
for (Map.Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
for (Map.Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
||||||
int packetId = entry.getKey();
|
int packetId = entry.getKey();
|
||||||
Class<?> packetClass = entry.getValue();
|
Class<?> packetClass = entry.getValue();
|
||||||
|
@ -509,9 +495,9 @@ public class PacketRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MinecraftVersion.v1_20_5.atOrAbove()) {
|
if (MinecraftVersion.v1_20_5.atOrAbove()) {
|
||||||
REGISTER = createNewNewRegister();
|
REGISTER = createRegisterV1_20_5();
|
||||||
} else if (MinecraftVersion.BEE_UPDATE.atOrAbove()) {
|
} else if (MinecraftVersion.BEE_UPDATE.atOrAbove()) {
|
||||||
REGISTER = createNewRegister();
|
REGISTER = createRegisterV1_15_0();
|
||||||
} else {
|
} else {
|
||||||
REGISTER = createOldRegister();
|
REGISTER = createOldRegister();
|
||||||
}
|
}
|
||||||
|
@ -522,6 +508,7 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the given packet type is supported on the current server.
|
* Determine if the given packet type is supported on the current server.
|
||||||
|
*
|
||||||
* @param type - the type to check.
|
* @param type - the type to check.
|
||||||
* @return TRUE if it is, FALSE otherwise.
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -532,6 +519,7 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve every known and supported server packet type.
|
* Retrieve every known and supported server packet type.
|
||||||
|
*
|
||||||
* @return Every server packet type.
|
* @return Every server packet type.
|
||||||
*/
|
*/
|
||||||
public static Set<PacketType> getServerPacketTypes() {
|
public static Set<PacketType> getServerPacketTypes() {
|
||||||
|
@ -543,6 +531,7 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve every known and supported server packet type.
|
* Retrieve every known and supported server packet type.
|
||||||
|
*
|
||||||
* @return Every server packet type.
|
* @return Every server packet type.
|
||||||
*/
|
*/
|
||||||
public static Set<PacketType> getClientPacketTypes() {
|
public static Set<PacketType> getClientPacketTypes() {
|
||||||
|
@ -560,7 +549,8 @@ public class PacketRegistry {
|
||||||
&& !Modifier.isAbstract(clazz.getModifiers())) {
|
&& !Modifier.isAbstract(clazz.getModifiers())) {
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -570,7 +560,8 @@ public class PacketRegistry {
|
||||||
* Retrieves the correct packet class from a given type.
|
* Retrieves the correct packet class from a given type.
|
||||||
*
|
*
|
||||||
* @param type - the packet type.
|
* @param type - the packet type.
|
||||||
* @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
|
* @param forceVanilla - whether or not to look for vanilla classes, not
|
||||||
|
* injected classes.
|
||||||
* @return The associated class.
|
* @return The associated class.
|
||||||
* @deprecated forceVanilla no longer has any effect
|
* @deprecated forceVanilla no longer has any effect
|
||||||
*/
|
*/
|
||||||
|
@ -594,21 +585,25 @@ public class PacketRegistry {
|
||||||
// Then try looking up the class names
|
// Then try looking up the class names
|
||||||
Class<?> clazz = searchForPacket(type.getClassNames());
|
Class<?> clazz = searchForPacket(type.getClassNames());
|
||||||
if (clazz != null) {
|
if (clazz != null) {
|
||||||
// we'd like for it to be associated correctly from the get-go; this is OK on older versions though
|
// we'd like for it to be associated correctly from the get-go; this is OK on
|
||||||
ProtocolLogger.warnAbove(type.getCurrentVersion(), "Updating associated class for {0} to {1}", type.name(), clazz);
|
// older versions though
|
||||||
|
ProtocolLogger.warnAbove(type.getCurrentVersion(), "Updating associated class for {0} to {1}", type.name(),
|
||||||
|
clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache it for next time
|
// cache it for next time
|
||||||
associate(type, clazz);
|
associate(type, clazz);
|
||||||
if (clazz != null && MinecraftReflection.isBundleDelimiter(clazz)) {
|
if (clazz != null && MinecraftReflection.isBundleDelimiter(clazz)) {
|
||||||
clazz = MinecraftReflection.getPackedBundlePacketClass().orElseThrow(() -> new IllegalStateException("Packet bundle class not found."));
|
clazz = MinecraftReflection.getPackedBundlePacketClass()
|
||||||
|
.orElseThrow(() -> new IllegalStateException("Packet bundle class not found."));
|
||||||
}
|
}
|
||||||
return Optional.ofNullable(clazz);
|
return Optional.ofNullable(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the packet class associated with a given type. First attempts to read from the
|
* Get the packet class associated with a given type. First attempts to read
|
||||||
* type-to-class mapping, and tries
|
* from the type-to-class mapping, and tries
|
||||||
|
*
|
||||||
* @param type the packet type
|
* @param type the packet type
|
||||||
* @return The associated class
|
* @return The associated class
|
||||||
*/
|
*/
|
||||||
|
@ -619,9 +614,11 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the packet type of a given packet.
|
* Retrieve the packet type of a given packet.
|
||||||
|
*
|
||||||
* @param packet - the class of the packet.
|
* @param packet - the class of the packet.
|
||||||
* @return The packet type, or NULL if not found.
|
* @return The packet type, or NULL if not found.
|
||||||
* @deprecated major issues due to packets with shared classes being registered in multiple states.
|
* @deprecated major issues due to packets with shared classes being registered
|
||||||
|
* in multiple states.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static PacketType getPacketType(Class<?> packet) {
|
public static PacketType getPacketType(Class<?> packet) {
|
||||||
|
@ -635,11 +632,13 @@ public class PacketRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the associated packet type for a packet class in the given protocol state.
|
* Retrieve the associated packet type for a packet class in the given protocol
|
||||||
|
* state.
|
||||||
*
|
*
|
||||||
* @param protocol the protocol state to retrieve the packet from.
|
* @param protocol the protocol state to retrieve the packet from.
|
||||||
* @param packet the class identifying the packet type.
|
* @param packet the class identifying the packet type.
|
||||||
* @return the packet type associated with the given class in the given protocol state, or null if not found.
|
* @return the packet type associated with the given class in the given protocol
|
||||||
|
* state, or null if not found.
|
||||||
*/
|
*/
|
||||||
public static PacketType getPacketType(PacketType.Protocol protocol, Class<?> packet) {
|
public static PacketType getPacketType(PacketType.Protocol protocol, Class<?> packet) {
|
||||||
initialize();
|
initialize();
|
||||||
|
@ -653,6 +652,7 @@ public class PacketRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the packet type of a given packet.
|
* Retrieve the packet type of a given packet.
|
||||||
|
*
|
||||||
* @param packet - the class of the packet.
|
* @param packet - the class of the packet.
|
||||||
* @param sender - the sender of the packet, or NULL.
|
* @param sender - the sender of the packet, or NULL.
|
||||||
* @return The packet type, or NULL if not found.
|
* @return The packet type, or NULL if not found.
|
||||||
|
|
|
@ -638,7 +638,8 @@ public final class MinecraftReflection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBundleDelimiter(Class<?> packetClass) {
|
public static boolean isBundleDelimiter(Class<?> packetClass) {
|
||||||
return Optionals.Equals(getBundleDelimiterClass(), packetClass);
|
Class<?> bundleDelimiterClass = getBundleDelimiterClass().orElse(null);
|
||||||
|
return bundleDelimiterClass != null && (packetClass.equals(bundleDelimiterClass) || bundleDelimiterClass.isAssignableFrom(packetClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<Class<?>> getBundleDelimiterClass() {
|
public static Optional<Class<?>> getBundleDelimiterClass() {
|
||||||
|
@ -1724,4 +1725,8 @@ public final class MinecraftReflection {
|
||||||
public static Class<?> getHolderLookupProviderClass() {
|
public static Class<?> getHolderLookupProviderClass() {
|
||||||
return getMinecraftClass("core.HolderLookup$a" /* Spigot Mappings */, "core.HolderLookup$Provider" /* Mojang Mappings */);
|
return getMinecraftClass("core.HolderLookup$a" /* Spigot Mappings */, "core.HolderLookup$Provider" /* Mojang Mappings */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Class<?> getProtocolInfoClass() {
|
||||||
|
return getMinecraftClass("network.ProtocolInfo");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,16 @@ import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static getter for the registry access accessor which is need for most of the methods
|
||||||
|
* since 1.20.5 that access the registry and in form.
|
||||||
|
*/
|
||||||
public class MinecraftRegistryAccess {
|
public class MinecraftRegistryAccess {
|
||||||
|
|
||||||
private static MethodAccessor GET_SERVER = null;
|
private static MethodAccessor GET_SERVER = null;
|
||||||
private static MethodAccessor REGISTRY_ACCESS = null;
|
private static MethodAccessor REGISTRY_ACCESS = null;
|
||||||
|
|
||||||
|
// lazy initialized
|
||||||
private static Object registryAccess = null;
|
private static Object registryAccess = null;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -34,6 +39,12 @@ public class MinecraftRegistryAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the composite global registry access. Equiv. of
|
||||||
|
* <pre>((CraftServer) Bukkit.getServer()).getServer().registryAccess()</pre>
|
||||||
|
*
|
||||||
|
* @return composite registy acesss
|
||||||
|
*/
|
||||||
public static Object get() {
|
public static Object get() {
|
||||||
if (GET_SERVER == null || REGISTRY_ACCESS == null) {
|
if (GET_SERVER == null || REGISTRY_ACCESS == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Reference in New Issue