Compare commits

...

2 Commits

Author SHA1 Message Date
Maurice Eisenblätter 70e3fd9a75
Merge 8d48e74f49 into e1255edb32 2024-04-24 16:30:35 +00:00
Maurice Eisenblätter 8d48e74f49
feat: add support for 1.20.5 2024-04-24 18:30:19 +02:00
5 changed files with 523 additions and 495 deletions

View File

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

View File

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

View File

@ -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
*/ */
@ -585,7 +576,7 @@ public class PacketRegistry {
// Try the lookup first (may be null, so check contains) // Try the lookup first (may be null, so check contains)
Optional<Class<?>> res = REGISTER.typeToClass.get(type); Optional<Class<?>> res = REGISTER.typeToClass.get(type);
if (res != null) { if (res != null) {
if(res.isPresent() && MinecraftReflection.isBundleDelimiter(res.get())) { if (res.isPresent() && MinecraftReflection.isBundleDelimiter(res.get())) {
return MinecraftReflection.getPackedBundlePacketClass(); return MinecraftReflection.getPackedBundlePacketClass();
} }
return res; return res;
@ -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.

View File

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

View File

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