From 9ca7c91a765f966f9a80e143ab3d20a8759ee172 Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Thu, 24 Jun 2021 17:14:00 -0400 Subject: [PATCH] Simplify packet registry --- .../com/comphenix/protocol/PacketType.java | 12 +- .../comphenix/protocol/PacketTypeEnum.java | 16 - .../protocol/concurrency/PacketTypeSet.java | 19 +- .../protocol/injector/ListenerInvoker.java | 8 - .../protocol/injector/PacketConstructor.java | 11 +- .../injector/PacketFilterManager.java | 6 - .../protocol/injector/StructureCache.java | 8 +- .../injector/netty/NettyProtocolRegistry.java | 222 ---------- .../injector/netty/ProtocolRegistry.java | 120 ------ .../injector/packet/PacketRegistry.java | 391 +++++++++++++----- .../protocol/utility/MinecraftReflection.java | 4 +- .../protocol/wrappers/EnumWrappers.java | 33 +- 12 files changed, 315 insertions(+), 535 deletions(-) delete mode 100644 src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java delete mode 100644 src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java diff --git a/src/main/java/com/comphenix/protocol/PacketType.java b/src/main/java/com/comphenix/protocol/PacketType.java index d63c6459..31cd0e21 100644 --- a/src/main/java/com/comphenix/protocol/PacketType.java +++ b/src/main/java/com/comphenix/protocol/PacketType.java @@ -187,7 +187,7 @@ public class PacketType implements Serializable, Cloneable, Comparable packetClass) { return PacketRegistry.getPacketType(packetClass) != null; } @@ -1090,11 +1092,7 @@ public class PacketType implements Serializable, Cloneable, Comparable getPacketClass() { - try { - return PacketRegistry.getPacketClassFromType(this); - } catch (Exception e) { - return null; - } + return PacketRegistry.tryGetPacketClass(this).orElse(null); } // Only used by Enum processor diff --git a/src/main/java/com/comphenix/protocol/PacketTypeEnum.java b/src/main/java/com/comphenix/protocol/PacketTypeEnum.java index ff6d065d..706e5eb1 100644 --- a/src/main/java/com/comphenix/protocol/PacketTypeEnum.java +++ b/src/main/java/com/comphenix/protocol/PacketTypeEnum.java @@ -110,22 +110,6 @@ public class PacketTypeEnum implements Iterable { public boolean hasMember(PacketType member) { return members.contains(member); } - - /** - * Retrieve a member by name, - * @param name - name of member to retrieve. - * @return The member, or NULL if not found. - * @deprecated Don't use this - */ - @Deprecated - public PacketType valueOf(String name) { - for (PacketType member : members) { - if (member.name().equals(name)) - return member; - } - - return null; - } /** * Retrieve every registered member. diff --git a/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java b/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java index fa5cc0e0..0b73e764 100644 --- a/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java +++ b/src/main/java/com/comphenix/protocol/concurrency/PacketTypeSet.java @@ -32,11 +32,11 @@ public class PacketTypeSet { * @param type - the type to add. */ public synchronized void addType(PacketType type) { - Class packetClass = getPacketClass(type); + Class packetClass = type.getPacketClass(); types.add(Preconditions.checkNotNull(type, "type cannot be NULL.")); if (packetClass != null) { - classes.add(getPacketClass(type)); + classes.add(type.getPacketClass()); } } @@ -55,11 +55,11 @@ public class PacketTypeSet { * @param type - the type to remove. */ public synchronized void removeType(PacketType type) { - Class packetClass = getPacketClass(type); + Class packetClass = type.getPacketClass(); types.remove(Preconditions.checkNotNull(type, "type cannot be NULL.")); if (packetClass != null) { - classes.remove(getPacketClass(type)); + classes.remove(packetClass); } } @@ -72,16 +72,7 @@ public class PacketTypeSet { removeType(type); } } - - /** - * Retrieve the packet class associated with a particular type. - * @param type - the packet type. - * @return The associated packet type. - */ - protected Class getPacketClass(PacketType type) { - return PacketRegistry.getPacketClassFromType(type); - } - + /** * Determine if the given packet type exists in the set. * @param type - the type to find. diff --git a/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java b/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java index a3e4ae41..3aecb517 100644 --- a/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java +++ b/src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java @@ -39,14 +39,6 @@ public interface ListenerInvoker { */ void invokePacketSending(PacketEvent event); - /** - * Retrieve the associated ID of a packet. - * @param packet - the packet. - * @return The packet ID. - */ - @Deprecated - int getPacketID(Object packet); - /** * Retrieve the associated type of a packet. * @param packet - the packet. diff --git a/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java b/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java index b6d49275..9e76d4e2 100644 --- a/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java +++ b/src/main/java/com/comphenix/protocol/injector/PacketConstructor.java @@ -20,6 +20,7 @@ package com.comphenix.protocol.injector; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.Optional; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.error.RethrowErrorReporter; @@ -146,13 +147,11 @@ public class PacketConstructor { types[i] = Object.class; } } - Class packetType = PacketRegistry.getPacketClassFromType(type, true); - - if (packetType == null) - throw new IllegalArgumentException("Could not find a packet by the type " + type); - + + Class packetClass = PacketRegistry.getPacketClassFromType(type); + // Find the correct constructor - for (Constructor constructor : packetType.getConstructors()) { + for (Constructor constructor : packetClass.getConstructors()) { Class[] params = constructor.getParameterTypes(); if (isCompatible(types, params)) { diff --git a/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index b74c5211..8aba85c4 100644 --- a/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -979,12 +979,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag return phaseLoginCount.get(); } - @Override - @Deprecated - public int getPacketID(Object packet) { - return PacketRegistry.getPacketID(packet.getClass()); - } - @Override public PacketType getPacketType(Object packet) { if (packet == null) diff --git a/src/main/java/com/comphenix/protocol/injector/StructureCache.java b/src/main/java/com/comphenix/protocol/injector/StructureCache.java index 790c4932..f2010253 100644 --- a/src/main/java/com/comphenix/protocol/injector/StructureCache.java +++ b/src/main/java/com/comphenix/protocol/injector/StructureCache.java @@ -92,11 +92,7 @@ public class StructureCache { * @return Created packet. */ public static Object newPacket(PacketType type) { - Class clazz = PacketRegistry.getPacketClassFromType(type, true); - if (clazz != null) { - return newPacket(clazz); - } - throw new IllegalArgumentException("Cannot find associated packet class: " + type); + return newPacket(PacketRegistry.getPacketClassFromType(type)); } /** @@ -146,7 +142,7 @@ public class StructureCache { if (result == null) { // Use the vanilla class definition final StructureModifier value = new StructureModifier<>( - PacketRegistry.getPacketClassFromType(type, true), MinecraftReflection.getPacketClass(), true); + PacketRegistry.getPacketClassFromType(type), MinecraftReflection.getPacketClass(), true); result = structureModifiers.putIfAbsent(type, value); diff --git a/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java b/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java deleted file mode 100644 index a929ff85..00000000 --- a/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.injector.netty; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Protocol; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.ProtocolLogger; -import com.comphenix.protocol.injector.packet.MapContainer; -import com.comphenix.protocol.reflect.FuzzyReflection; -import com.comphenix.protocol.reflect.StructureModifier; -import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.google.common.collect.Maps; - -/** - * @author dmulloy2 - */ - -public class NettyProtocolRegistry extends ProtocolRegistry { - - public NettyProtocolRegistry() { - super(); - } - - @Override - protected synchronized void initialize() { - if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BEE_UPDATE)) { - initializeNew(); - return; - } - - Object[] protocols = enumProtocol.getEnumConstants(); - - // ID to Packet class maps - Map>> serverMaps = Maps.newLinkedHashMap(); - Map>> clientMaps = Maps.newLinkedHashMap(); - - Register result = new Register(); - StructureModifier modifier = null; - - // Iterate through the protocols - for (Object protocol : protocols) { - if (modifier == null) { - modifier = new StructureModifier(protocol.getClass().getSuperclass(), false); - } - - StructureModifier>>> maps = modifier.withTarget(protocol).withType(Map.class); - for (Entry>> entry : maps.read(0).entrySet()) { - String direction = entry.getKey().toString(); - if (direction.contains("CLIENTBOUND")) { // Sent by Server - serverMaps.put(protocol, entry.getValue()); - } else if (direction.contains("SERVERBOUND")) { // Sent by Client - clientMaps.put(protocol, entry.getValue()); - } - } - } - - // Maps we have to occasionally check have changed - for (Object map : serverMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (Object map : clientMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (Object protocol : protocols) { - Enum enumProtocol = (Enum) protocol; - Protocol equivalent = Protocol.fromVanilla(enumProtocol); - - // Associate known types - if (serverMaps.containsKey(protocol)) - associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER); - if (clientMaps.containsKey(protocol)) - associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT); - } - - // Exchange (thread safe, as we have only one writer) - this.register = result; - } - - @SuppressWarnings("unchecked") - private synchronized void initializeNew() { - Object[] protocols = enumProtocol.getEnumConstants(); - - // ID to Packet class maps - Map, Integer>> serverMaps = Maps.newLinkedHashMap(); - Map, Integer>> clientMaps = Maps.newLinkedHashMap(); - - Register result = new Register(); - Field mainMapField = null; - Field packetMapField = null; - - // Iterate through the protocols - for (Object protocol : protocols) { - if (mainMapField == null) { - FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true); - mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder() - .banModifier(Modifier.STATIC) - .requireModifier(Modifier.FINAL) - .typeDerivedOf(Map.class) - .build()); - mainMapField.setAccessible(true); - } - - Map directionMap; - - try { - directionMap = (Map) mainMapField.get(protocol); - } catch (ReflectiveOperationException ex) { - throw new RuntimeException("Failed to access packet map", ex); - } - - for (Entry entry : directionMap.entrySet()) { - Object holder = entry.getValue(); - if (packetMapField == null) { - FuzzyReflection fuzzy = FuzzyReflection.fromClass(holder.getClass(), true); - packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder() - .banModifier(Modifier.STATIC) - .requireModifier(Modifier.FINAL) - .typeDerivedOf(Map.class) - .build()); - packetMapField.setAccessible(true); - } - - Map, Integer> packetMap; - - try { - packetMap = (Map, Integer>) packetMapField.get(holder); - } catch (ReflectiveOperationException ex) { - throw new RuntimeException("Failed to access packet map", ex); - } - - String direction = entry.getKey().toString(); - if (direction.contains("CLIENTBOUND")) { // Sent by Server - serverMaps.put(protocol, packetMap); - } else if (direction.contains("SERVERBOUND")) { // Sent by Client - clientMaps.put(protocol, packetMap); - } - } - } - - // Maps we have to occasionally check have changed - // TODO: Find equivalent in Object2IntMap - - /* for (Object map : serverMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (Object map : clientMaps.values()) { - result.containers.add(new MapContainer(map)); - } */ - - for (Object protocol : protocols) { - Enum enumProtocol = (Enum) protocol; - Protocol equivalent = Protocol.fromVanilla(enumProtocol); - - // Associate known types - if (serverMaps.containsKey(protocol)) { - associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER); - } - if (clientMaps.containsKey(protocol)) { - associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT); - } - } - - // Exchange (thread safe, as we have only one writer) - this.register = result; - } - - /** - * Reverses a key->value map to value->key - * Non-deterministic behavior when multiple keys are mapped to the same value - */ - private Map reverse(Map map) { - Map newMap = new HashMap<>(map.size()); - for (Entry entry : map.entrySet()) { - newMap.put(entry.getValue(), entry.getKey()); - } - return newMap; - } - - @Override - protected void associatePackets(Register register, Map> lookup, Protocol protocol, Sender sender) { - for (Entry> entry : lookup.entrySet()) { - PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue()); - // System.out.println(Arrays.toString(type.getClassNames()) + " -> " + entry.getValue()); - - try { - register.typeToClass.put(type, entry.getValue()); - - if (sender == Sender.SERVER) - register.serverPackets.add(type); - if (sender == Sender.CLIENT) - register.clientPackets.add(type); - } catch (Exception ex) { - ProtocolLogger.debug("Encountered an exception associating packet " + type, ex); - } - } - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java b/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java deleted file mode 100644 index 65bfc9ed..00000000 --- a/src/main/java/com/comphenix/protocol/injector/netty/ProtocolRegistry.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.comphenix.protocol.injector.netty; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.PacketType.Protocol; -import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.injector.packet.MapContainer; -import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -/** - * Represents a way of accessing the new netty Protocol enum. - * @author Kristian - */ - -public abstract class ProtocolRegistry { - /** - * Represents a register we are currently building. - * @author Kristian - */ - protected static class Register { - // The main lookup table - public BiMap> typeToClass = HashBiMap.create(); - public volatile Set serverPackets = Sets.newHashSet(); - public volatile Set clientPackets = Sets.newHashSet(); - public List containers = Lists.newArrayList(); - - public Register() { - } - - /** - * Determine if the current register is outdated. - * @return TRUE if it is, FALSE otherwise. - */ - public boolean isOutdated() { - for (MapContainer container : containers) { - if (container.hasChanged()) { - return true; - } - } - return false; - } - } - - protected Class enumProtocol; - - // Current register - protected volatile Register register; - - public ProtocolRegistry() { - enumProtocol = MinecraftReflection.getEnumProtocolClass(); - initialize(); - } - - /** - * Retrieve an immutable view of the packet type lookup. - * @return The packet type lookup. - */ - public Map> getPacketTypeLookup() { - return Collections.unmodifiableMap(register.typeToClass); - } - - /** - * Retrieve an immutable view of the class to packet type lookup. - * @return The packet type lookup. - */ - public Map, PacketType> getPacketClassLookup() { - return Collections.unmodifiableMap(register.typeToClass.inverse()); - } - - /** - * Retrieve every known client packet, from every protocol. - * @return Every client packet. - */ - public Set getClientPackets() { - return Collections.unmodifiableSet(register.clientPackets); - } - - /** - * Retrieve every known server packet, from every protocol. - * @return Every server packet. - */ - public Set getServerPackets() { - return Collections.unmodifiableSet(register.serverPackets); - } - - /** - * Ensure that our local register is up-to-date with Minecraft. - *

- * This operation may block the calling thread. - */ - public synchronized void synchronize() { - // Check if the packet registry has changed - if (register.isOutdated()) { - initialize(); - } - } - - /** - * Load the packet lookup tables in each protocol. - */ - protected abstract void initialize(); - - protected abstract void associatePackets(Register register, Map> lookup, Protocol protocol, Sender sender); - - /** - * @deprecated Not a public API - */ - @Deprecated - public void _associate(PacketType type, Class clazz) { - register.typeToClass.put(type, clazz); - } -} diff --git a/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java b/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java index 2e1bc8b4..b10e51a9 100644 --- a/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java +++ b/src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java @@ -17,44 +17,275 @@ package com.comphenix.protocol.injector.packet; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.PacketType.Sender; -import com.comphenix.protocol.injector.netty.NettyProtocolRegistry; -import com.comphenix.protocol.injector.netty.ProtocolRegistry; +import com.comphenix.protocol.ProtocolLogger; +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; import com.comphenix.protocol.utility.MinecraftReflection; -import com.google.common.base.Function; +import com.comphenix.protocol.utility.MinecraftVersion; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; /** * Static packet registry in Minecraft. * @author Kristian */ -@SuppressWarnings("rawtypes") public class PacketRegistry { - // The Netty packet registry - private static volatile ProtocolRegistry NETTY; - // Whether or not the registry has been initialized private static volatile boolean INITIALIZED = false; + /** + * Represents a register we are currently building. + * @author Kristian + */ + protected static class Register { + // The main lookup table + private final Map>> typeToClass = new ConcurrentHashMap<>(); + private final Map, PacketType> classToType = new ConcurrentHashMap<>(); + + private volatile Set serverPackets = Sets.newHashSet(); + private volatile Set clientPackets = Sets.newHashSet(); + private final List containers = Lists.newArrayList(); + + public Register() {} + + public void registerPacket(PacketType type, Class clazz, Sender sender) { + typeToClass.put(type, Optional.of(clazz)); + classToType.put(clazz, type); + if (sender == Sender.CLIENT) { + clientPackets.add(type); + } else { + serverPackets.add(type); + } + } + + public void addContainer(MapContainer container) { + containers.add(container); + } + + /** + * Determine if the current register is outdated. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean isOutdated() { + for (MapContainer container : containers) { + if (container.hasChanged()) { + return true; + } + } + return false; + } + } + + protected static final Class ENUM_PROTOCOL = MinecraftReflection.getEnumProtocolClass(); + + // Current register + protected static volatile Register REGISTER; + + /** + * Ensure that our local register is up-to-date with Minecraft. + *

+ * This operation may block the calling thread. + */ + public static synchronized void synchronize() { + // Check if the packet registry has changed + if (REGISTER.isOutdated()) { + initialize(); + } + } + + protected static synchronized Register createOldRegister() { + Object[] protocols = ENUM_PROTOCOL.getEnumConstants(); + + // ID to Packet class maps + Map>> serverMaps = Maps.newLinkedHashMap(); + Map>> clientMaps = Maps.newLinkedHashMap(); + + Register result = new Register(); + StructureModifier modifier = null; + + // Iterate through the protocols + for (Object protocol : protocols) { + if (modifier == null) { + modifier = new StructureModifier<>(protocol.getClass().getSuperclass(), false); + } + + StructureModifier>>> maps = modifier.withTarget(protocol).withType(Map.class); + for (Map.Entry>> entry : maps.read(0).entrySet()) { + String direction = entry.getKey().toString(); + if (direction.contains("CLIENTBOUND")) { // Sent by Server + serverMaps.put(protocol, entry.getValue()); + } else if (direction.contains("SERVERBOUND")) { // Sent by Client + clientMaps.put(protocol, entry.getValue()); + } + } + } + + // Maps we have to occasionally check have changed + for (Object map : serverMaps.values()) { + REGISTER.addContainer(new MapContainer(map)); + } + + for (Object map : clientMaps.values()) { + REGISTER.addContainer(new MapContainer(map)); + } + + for (Object protocol : protocols) { + Enum enumProtocol = (Enum) protocol; + PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol); + + // Associate known types + if (serverMaps.containsKey(protocol)) + associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER); + if (clientMaps.containsKey(protocol)) + associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT); + } + + return result; + } + + @SuppressWarnings("unchecked") + private static synchronized Register createNewRegister() { + Object[] protocols = ENUM_PROTOCOL.getEnumConstants(); + + // ID to Packet class maps + Map, Integer>> serverMaps = Maps.newLinkedHashMap(); + Map, Integer>> clientMaps = Maps.newLinkedHashMap(); + + Register result = new Register(); + Field mainMapField = null; + Field packetMapField = null; + + // Iterate through the protocols + for (Object protocol : protocols) { + if (mainMapField == null) { + FuzzyReflection fuzzy = FuzzyReflection.fromClass(protocol.getClass(), true); + mainMapField = fuzzy.getField(FuzzyFieldContract.newBuilder() + .banModifier(Modifier.STATIC) + .requireModifier(Modifier.FINAL) + .typeDerivedOf(Map.class) + .build()); + mainMapField.setAccessible(true); + } + + Map directionMap; + + try { + directionMap = (Map) mainMapField.get(protocol); + } catch (ReflectiveOperationException ex) { + throw new RuntimeException("Failed to access packet map", ex); + } + + for (Map.Entry entry : directionMap.entrySet()) { + Object holder = entry.getValue(); + if (packetMapField == null) { + FuzzyReflection fuzzy = FuzzyReflection.fromClass(holder.getClass(), true); + packetMapField = fuzzy.getField(FuzzyFieldContract.newBuilder() + .banModifier(Modifier.STATIC) + .requireModifier(Modifier.FINAL) + .typeDerivedOf(Map.class) + .build()); + packetMapField.setAccessible(true); + } + + Map, Integer> packetMap; + + try { + packetMap = (Map, Integer>) packetMapField.get(holder); + } catch (ReflectiveOperationException ex) { + throw new RuntimeException("Failed to access packet map", ex); + } + + String direction = entry.getKey().toString(); + if (direction.contains("CLIENTBOUND")) { // Sent by Server + serverMaps.put(protocol, packetMap); + } else if (direction.contains("SERVERBOUND")) { // Sent by Client + clientMaps.put(protocol, packetMap); + } + } + } + + // Maps we have to occasionally check have changed + // TODO: Find equivalent in Object2IntMap + + /* for (Object map : serverMaps.values()) { + result.containers.add(new MapContainer(map)); + } + + for (Object map : clientMaps.values()) { + result.containers.add(new MapContainer(map)); + } */ + + for (Object protocol : protocols) { + Enum enumProtocol = (Enum) protocol; + PacketType.Protocol equivalent = PacketType.Protocol.fromVanilla(enumProtocol); + + // Associate known types + if (serverMaps.containsKey(protocol)) { + associatePackets(result, reverse(serverMaps.get(protocol)), equivalent, Sender.SERVER); + } + if (clientMaps.containsKey(protocol)) { + associatePackets(result, reverse(clientMaps.get(protocol)), equivalent, Sender.CLIENT); + } + } + + return result; + } + + /** + * Reverses a key->value map to value->key + * Non-deterministic behavior when multiple keys are mapped to the same value + */ + private static Map reverse(Map map) { + Map newMap = new HashMap<>(map.size()); + for (Map.Entry entry : map.entrySet()) { + newMap.put(entry.getValue(), entry.getKey()); + } + return newMap; + } + + protected static void associatePackets(Register register, Map> lookup, PacketType.Protocol protocol, Sender sender) { + for (Map.Entry> entry : lookup.entrySet()) { + PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue()); + + try { + register.registerPacket(type, entry.getValue(), sender); + } catch (Exception ex) { + ProtocolLogger.debug("Encountered an exception associating packet " + type, ex); + } + } + } + + private static void associate(PacketType type, Class clazz) { + if (clazz != null) { + REGISTER.typeToClass.put(type, Optional.of(clazz)); + REGISTER.classToType.put(clazz, type); + } else { + REGISTER.typeToClass.put(type, Optional.empty()); + } + } + /** * Initializes the packet registry. */ private static void initialize() { - if (INITIALIZED) { - if (NETTY == null) { - throw new IllegalStateException("Failed to initialize packet registry."); - } - return; - } + if (!INITIALIZED) { + INITIALIZED = true; - NETTY = new NettyProtocolRegistry(); - INITIALIZED = true; + if (MinecraftVersion.BEE_UPDATE.atOrAbove()) { + REGISTER = createNewRegister(); + } else { + REGISTER = createOldRegister(); + } + } } /** @@ -64,35 +295,7 @@ public class PacketRegistry { */ public static boolean isSupported(PacketType type) { initialize(); - return NETTY.getPacketTypeLookup().get(type) != null; - } - - /** - * Retrieve a map of every packet class to every ID. - *

- * Deprecated: Use {@link #getPacketToType()} instead. - * @return A map of packet classes and their corresponding ID. - */ - @Deprecated - public static Map getPacketToID() { - initialize(); - - @SuppressWarnings("unchecked") - Map result = (Map) Maps.transformValues( - NETTY.getPacketClassLookup(), PacketType::getCurrentId); - return result; - } - - /** - * Retrieve a map of every packet class to the respective packet type. - * @return A map of packet classes and their corresponding packet type. - */ - public static Map getPacketToType() { - initialize(); - - @SuppressWarnings("unchecked") - Map result = (Map) NETTY.getPacketClassLookup(); - return result; + return tryGetPacketClass(type).isPresent(); } /** @@ -101,9 +304,9 @@ public class PacketRegistry { */ public static Set getServerPacketTypes() { initialize(); - NETTY.synchronize(); + synchronize(); - return NETTY.getServerPackets(); + return Collections.unmodifiableSet(REGISTER.serverPackets); } /** @@ -112,31 +315,9 @@ public class PacketRegistry { */ public static Set getClientPacketTypes() { initialize(); - NETTY.synchronize(); + synchronize(); - return NETTY.getClientPackets(); - } - - /** - * Retrieves the correct packet class from a given packet ID. - *

- * Deprecated: Use {@link #getPacketClassFromType(PacketType)} instead. - * @param packetID - the packet ID. - * @return The associated class. - */ - @Deprecated - public static Class getPacketClassFromID(int packetID) { - initialize(); - return NETTY.getPacketTypeLookup().get(PacketType.findLegacy(packetID)); - } - - /** - * Retrieves the correct packet class from a given type. - * @param type - the packet type. - * @return The associated class. - */ - public static Class getPacketClassFromType(PacketType type) { - return getPacketClassFromType(type, false); + return Collections.unmodifiableSet(REGISTER.clientPackets); } private static Class searchForPacket(List classNames) { @@ -155,55 +336,43 @@ public class PacketRegistry { /** * Retrieves the correct packet class from a given type. - *

- * Note that forceVanillla will be ignored on MC 1.7.2 and later. + * * @param type - the packet type. * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. * @return The associated class. + * @deprecated forceVanilla no longer has any effect */ - public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) { + @Deprecated + public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) { + return getPacketClassFromType(type); + } + + public static Optional> tryGetPacketClass(PacketType type) { initialize(); - // Try the lookup first - Class clazz = NETTY.getPacketTypeLookup().get(type); - if (clazz != null) { - return clazz; + // Try the lookup first (may be null, so check contains) + Optional> res = REGISTER.typeToClass.get(type); + if (res != null) { + return res; } // Then try looking up the class names - clazz = searchForPacket(type.getClassNames()); + Class clazz = searchForPacket(type.getClassNames()); // cache it for next time - NETTY._associate(type, clazz); - return clazz; + associate(type, clazz); + return Optional.ofNullable(clazz); } /** - * Retrieves the correct packet class from a given packet ID. - *

- * This method has been deprecated. - * @param packetID - the packet ID. - * @param forceVanilla - whether or not to look for vanilla classes, not injected classes. - * @return The associated class. + * Get the packet class associated with a given type. First attempts to read from the + * type-to-class mapping, and tries + * @param type the packet type + * @return The associated class */ - @Deprecated - public static Class getPacketClassFromID(int packetID, boolean forceVanilla) { - initialize(); - return getPacketClassFromID(packetID); - } - - /** - * Retrieve the packet ID of a given packet. - *

- * Deprecated: Use {@link #getPacketType(Class)}. - * @param packet - the type of packet to check. - * @return The legacy ID of the given packet. - * @throws IllegalArgumentException If this is not a valid packet. - */ - @Deprecated - public static int getPacketID(Class packet) { - initialize(); - return NETTY.getPacketClassLookup().get(packet).getCurrentId(); + public static Class getPacketClassFromType(PacketType type) { + return tryGetPacketClass(type) + .orElseThrow(() -> new IllegalArgumentException("Could not find packet for type " + type.name())); } /** @@ -212,7 +381,8 @@ public class PacketRegistry { * @return The packet type, or NULL if not found. */ public static PacketType getPacketType(Class packet) { - return getPacketType(packet, null); + initialize(); + return REGISTER.classToType.get(packet); } /** @@ -220,9 +390,10 @@ public class PacketRegistry { * @param packet - the class of the packet. * @param sender - the sender of the packet, or NULL. * @return The packet type, or NULL if not found. + * @deprecated sender no longer has any effect */ + @Deprecated public static PacketType getPacketType(Class packet, Sender sender) { - initialize(); - return NETTY.getPacketClassLookup().get(packet); + return getPacketType(packet); } } diff --git a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 570f221b..f1b06863 100644 --- a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1292,7 +1292,7 @@ public class MinecraftReflection { try { return getMinecraftClass("world.level.ChunkCoordIntPair", "ChunkCoordIntPair"); } catch (RuntimeException e) { - Class packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.MULTI_BLOCK_CHANGE); + Class packet = PacketType.Play.Server.MULTI_BLOCK_CHANGE.getPacketClass(); AbstractFuzzyMatcher> chunkCoordIntContract = FuzzyClassContract.newBuilder(). field(FuzzyFieldContract.newBuilder(). @@ -1640,7 +1640,7 @@ public class MinecraftReflection { return getMinecraftClass("world.effect.MobEffect", "MobEffect"); } catch (RuntimeException e) { // It is the second parameter in Packet41MobEffect - Class packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.ENTITY_EFFECT); + Class packet = PacketType.Play.Server.ENTITY_EFFECT.getPacketClass(); Constructor constructor = FuzzyReflection.fromClass(packet).getConstructor( FuzzyMethodContract.newBuilder(). parameterCount(2). diff --git a/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java b/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java index 6d921422..4f3ef702 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java +++ b/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java @@ -557,12 +557,18 @@ public abstract class EnumWrappers { * @return The type of the enum field. */ private static Class getEnum(Class clazz, int index) { - try { - return FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class).get(index).getType(); - } catch (Throwable ex) { - ProtocolLogger.debug("Exception getting enum from " + clazz + " at index " + index, ex); + if (clazz == null) { + // not supported in the current version return null; } + + List enumFields = FuzzyReflection.fromClass(clazz, true).getFieldListByType(Enum.class); + if (enumFields.size() <= index) { + // also probably not supported + return null; + } + + return enumFields.get(index).getType(); } public static Map, EquivalentConverter> getFromNativeMap() { @@ -779,22 +785,17 @@ public abstract class EnumWrappers { return new EnumConverter<>(genericClass, specificType); } - /** - * @deprecated Replaced with {@link #getGenericConverter(Class, Class)} - */ - @Deprecated - public static > EquivalentConverter getGenericConverter(Class specificType) { - return new EnumConverter<>(null, specificType); - } - /** * The common Enum converter */ public static class EnumConverter> implements EquivalentConverter { - private Class genericType; - private Class specificType; + private final Class genericType; + private final Class specificType; public EnumConverter(Class genericType, Class specificType) { + Validate.notNull(specificType, "specificType cannot be null"); + // would love to check if genericType is null, but it breaks other stuff + this.genericType = genericType; this.specificType = specificType; } @@ -813,10 +814,6 @@ public abstract class EnumWrappers { public Class getSpecificType() { return specificType; } - - void setGenericType(Class genericType) { - this.genericType = genericType; - } } public interface AliasedEnum {