diff --git a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java index dbb27ab0..e06f7a10 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java +++ b/modules/API/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolRegistry.java @@ -1,104 +1,108 @@ -/** - * 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.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.injector.netty.ProtocolRegistry; -import com.comphenix.protocol.injector.packet.MapContainer; -import com.comphenix.protocol.reflect.StructureModifier; -import com.google.common.collect.Maps; - -/** - * @author dmulloy2 - */ - -public class NettyProtocolRegistry extends ProtocolRegistry { - - @Override - protected synchronized void initialize() { - 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 occationally check have changed - for (Map> map : serverMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (Map> map : clientMaps.values()) { - result.containers.add(new MapContainer(map)); - } - - for (int i = 0; i < protocols.length; i++) { - Object protocol = protocols[i]; - 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; - } - - @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()); - - try { - register.typeToClass.put(type, entry.getValue()); - - if (sender == Sender.SERVER) - register.serverPackets.add(type); - if (sender == Sender.CLIENT) - register.clientPackets.add(type); - } catch (IllegalArgumentException ex) { - // Sometimes this happens with fake packets, just ignore it - } - } - } -} +/** + * 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.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.injector.netty.ProtocolRegistry; +import com.comphenix.protocol.injector.packet.MapContainer; +import com.comphenix.protocol.reflect.StructureModifier; +import com.google.common.collect.Maps; + +/** + * @author dmulloy2 + */ + +public class NettyProtocolRegistry extends ProtocolRegistry { + + public NettyProtocolRegistry() { + super(); + } + + @Override + protected synchronized void initialize() { + 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 (Map> map : serverMaps.values()) { + result.containers.add(new MapContainer(map)); + } + + for (Map> map : clientMaps.values()) { + result.containers.add(new MapContainer(map)); + } + + for (int i = 0; i < protocols.length; i++) { + Object protocol = protocols[i]; + 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; + } + + @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()); + + try { + register.typeToClass.put(type, entry.getValue()); + + if (sender == Sender.SERVER) + register.serverPackets.add(type); + if (sender == Sender.CLIENT) + register.clientPackets.add(type); + } catch (IllegalArgumentException ex) { + // Sometimes this happens with fake packets, just ignore it + } + } + } +} diff --git a/modules/API/src/main/java/com/comphenix/protocol/reflect/FuzzyReflection.java b/modules/API/src/main/java/com/comphenix/protocol/reflect/FuzzyReflection.java index c539dc8b..df3ec791 100644 --- a/modules/API/src/main/java/com/comphenix/protocol/reflect/FuzzyReflection.java +++ b/modules/API/src/main/java/com/comphenix/protocol/reflect/FuzzyReflection.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.Set; import java.util.regex.Pattern; +import org.apache.commons.lang.Validate; + import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher; import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; @@ -577,6 +579,8 @@ public class FuzzyReflection { * @return Every field. */ public Set getFields() { + Validate.notNull(source, "source cannot be null!"); + // We will only consider private fields in the declared class if (forceAccess) return setUnion(source.getDeclaredFields(), source.getFields()); diff --git a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java index b6283e37..2f59382b 100644 --- a/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java +++ b/modules/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java @@ -582,26 +582,35 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector { * @param packet - the packet. */ protected void handleLogin(Class packetClass, Object packet) { - Class loginClass = PACKET_LOGIN_CLIENT; - FieldAccessor loginClient = LOGIN_GAME_PROFILE; + try { + Class loginClass = PACKET_LOGIN_CLIENT; + FieldAccessor loginClient = LOGIN_GAME_PROFILE; - // Initialize packet class and login - if (loginClass == null) { - loginClass = PacketType.Login.Client.START.getPacketClass(); - PACKET_LOGIN_CLIENT = loginClass; - } - if (loginClient == null) { - loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true); - LOGIN_GAME_PROFILE = loginClient; - } + // Initialize packet class and login + if (loginClass == null) { + loginClass = PacketType.Login.Client.START.getPacketClass(); + PACKET_LOGIN_CLIENT = loginClass; + } + if (loginClient == null) { + loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true); + LOGIN_GAME_PROFILE = loginClient; + } - // See if we are dealing with the login packet - if (loginClass.equals(packetClass)) { - // GameProfile profile = (GameProfile) loginClient.get(packet); - WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet)); + // See if we are dealing with the login packet + if (loginClass.equals(packetClass)) { + // GameProfile profile = (GameProfile) loginClient.get(packet); + WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet)); - // Save the channel injector - factory.cacheInjector(profile.getName(), this); + // Save the channel injector + factory.cacheInjector(profile.getName(), this); + } + } catch (NullPointerException ex) { + System.err.println(String.format("[ProtocolLib] Encountered NPE in handleLogin(%s, %s)", packetClass, packet)); + System.err.println("PACKET_LOGIN_CLIENT = " + PACKET_LOGIN_CLIENT); + System.err.println("LOGIN_GAME_PROFILE = " + LOGIN_GAME_PROFILE); + System.err.println("GameProfile class = " + MinecraftReflection.getGameProfileClass()); + System.err.println("Provide this information in a new or existing issue"); + throw ex; } } diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java index 1a2ed68c..ed780d6a 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/PacketTypeTest.java @@ -14,6 +14,8 @@ import com.comphenix.protocol.PacketType.Sender; import com.comphenix.protocol.injector.netty.NettyProtocolRegistry; import com.comphenix.protocol.injector.netty.ProtocolRegistry; +import net.minecraft.server.v1_9_R2.PacketLoginInStart; + public class PacketTypeTest { @BeforeClass @@ -26,6 +28,12 @@ public class PacketTypeTest { assertEquals(PacketType.Play.Client.STEER_VEHICLE, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle")); } + @Test + public void testLoginStart() { + // This packet is critical for handleLoin + assertEquals(PacketLoginInStart.class, PacketType.Login.Client.START.getPacketClass()); + } + @Test public void ensureAllExist() { boolean missing = false; diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java index 83f781ec..39e19837 100644 --- a/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java +++ b/modules/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java @@ -4,18 +4,6 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import net.minecraft.server.v1_9_R2.ChatComponentText; -import net.minecraft.server.v1_9_R2.ChunkCoordIntPair; -import net.minecraft.server.v1_9_R2.DataWatcher; -import net.minecraft.server.v1_9_R2.IBlockData; -import net.minecraft.server.v1_9_R2.IChatBaseComponent; -import net.minecraft.server.v1_9_R2.IChatBaseComponent.ChatSerializer; -import net.minecraft.server.v1_9_R2.NBTCompressedStreamTools; -import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot; -import net.minecraft.server.v1_9_R2.PlayerConnection; -import net.minecraft.server.v1_9_R2.ServerPing; -import net.minecraft.server.v1_9_R2.ServerPing.ServerData; -import net.minecraft.server.v1_9_R2.ServerPing.ServerPingPlayerSample; import org.bukkit.Material; import org.bukkit.block.Block; @@ -28,6 +16,20 @@ import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; import com.comphenix.protocol.BukkitInitialization; +import com.mojang.authlib.GameProfile; + +import net.minecraft.server.v1_9_R2.ChatComponentText; +import net.minecraft.server.v1_9_R2.ChunkCoordIntPair; +import net.minecraft.server.v1_9_R2.DataWatcher; +import net.minecraft.server.v1_9_R2.IBlockData; +import net.minecraft.server.v1_9_R2.IChatBaseComponent; +import net.minecraft.server.v1_9_R2.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_9_R2.NBTCompressedStreamTools; +import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot; +import net.minecraft.server.v1_9_R2.PlayerConnection; +import net.minecraft.server.v1_9_R2.ServerPing; +import net.minecraft.server.v1_9_R2.ServerPing.ServerData; +import net.minecraft.server.v1_9_R2.ServerPing.ServerPingPlayerSample; @RunWith(org.powermock.modules.junit4.PowerMockRunner.class) @PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" }) @@ -136,4 +138,9 @@ public class MinecraftReflectionTest { Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack); assertEquals(stack, MinecraftReflection.getBukkitItemStack(nmsStack)); } + + @Test + public void testGameProfile() { + assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass()); + } } \ No newline at end of file