From 84ce20f202a13813f130b4a58f771a238734d897 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Fri, 6 Dec 2013 02:31:50 +0100 Subject: [PATCH] Added a GameProfile wrapper class. Easy enough, as we don't have to use reflection. --- .../protocol/events/PacketContainer.java | 15 +++ .../protocol/utility/MinecraftReflection.java | 14 +++ .../protocol/wrappers/BukkitConverters.java | 23 ++++ .../protocol/wrappers/WrappedGameProfile.java | 104 ++++++++++++++++++ .../protocol/events/PacketContainerTest.java | 10 ++ .../utility/MinecraftReflectionTest.java | 3 +- 6 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java index 338aaac7..87f0139c 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.minecraft.util.com.mojang.authlib.GameProfile; import net.minecraft.util.io.netty.buffer.ByteBuf; import net.minecraft.util.io.netty.buffer.UnpooledByteBufAllocator; import org.bukkit.World; @@ -66,6 +67,7 @@ import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.WrappedAttribute; import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.comphenix.protocol.wrappers.WrappedWatchableObject; import com.comphenix.protocol.wrappers.nbt.NbtBase; import com.google.common.base.Function; @@ -475,6 +477,19 @@ public class PacketContainer implements Serializable { ); } + /** + * Retrieves a read/write structure for game profiles. + *

+ * This modifier will automatically marshall between WrappedGameProfile and the + * internal Minecraft GameProfile. + * @return A modifier for GameProfile fields. + */ + public StructureModifier getGameProfiles() { + // Convert to and from the Bukkit wrapper + return structureModifier.withType( + GameProfile.class, BukkitConverters.getWrappedGameProfileConverter()); + } + /** * Retrieves the ID of this packet. *

diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 381803a0..c552ae72 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -35,6 +35,7 @@ import java.util.regex.Pattern; import javax.annotation.Nonnull; +import net.minecraft.util.com.mojang.authlib.GameProfile; import net.minecraft.util.io.netty.buffer.ByteBuf; import net.sf.cglib.asm.ClassReader; import net.sf.cglib.asm.MethodVisitor; @@ -517,6 +518,19 @@ public class MinecraftReflection { } } + /** + * Retrieve the GameProfile class in 1.7.2 and later. + * @return The game profile class. + * @throws IllegalStateException If we are running 1.6.4 or earlier. + */ + public static Class getGameProfileClass() { + if (!isUsingNetty()) + throw new IllegalStateException("GameProfile does not exist in version 1.6.4 and earlier."); + + // Yay, we can actually refer to it directly + return GameProfile.class; + } + /** * Retrieve the entity (NMS) class. * @return The entity class. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java index 2d2ea72f..301f9a0f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java @@ -234,6 +234,29 @@ public class BukkitConverters { }; } + /** + * Retrieve a converter for wrapped attribute snapshots. + * @return Wrapped attribute snapshot converter. + */ + public static EquivalentConverter getWrappedGameProfileConverter() { + return new IgnoreNullConverter() { + @Override + protected Object getGenericValue(Class genericType, WrappedGameProfile specific) { + return specific.getHandle(); + } + + @Override + protected WrappedGameProfile getSpecificValue(Object generic) { + return WrappedGameProfile.fromHandle(generic); + } + + @Override + public Class getSpecificType() { + return WrappedGameProfile.class; + } + }; + } + /** * Retrieve a converter for wrapped attribute snapshots. * @return Wrapped attribute snapshot converter. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java new file mode 100644 index 00000000..f390b208 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedGameProfile.java @@ -0,0 +1,104 @@ +package com.comphenix.protocol.wrappers; + +import net.minecraft.util.com.mojang.authlib.GameProfile; + +/** + * Represents a wrapper for a game profile. + * @author Kristian + */ +public class WrappedGameProfile { + private GameProfile profile; + + // Profile from a handle + private WrappedGameProfile(Object profile) { + if (profile == null) + throw new IllegalArgumentException("Profile cannot be NULL."); + if (!(profile instanceof GameProfile)) + throw new IllegalArgumentException(profile + " is not a GameProfile"); + this.profile = (GameProfile) profile; + } + + /** + * Construct a new game profile with the given properties. + * @param id - the UUID of the player. + * @param name - the name of the player. + */ + public WrappedGameProfile(String id, String name) { + this(new GameProfile(id, name)); + } + + /** + * Construct a wrapper around an existing game profile. + * @param profile - the underlying profile. + */ + public static WrappedGameProfile fromHandle(Object handle) { + return new WrappedGameProfile(handle); + } + + /** + * Retrieve the underlying game profile. + * @return The profile. + */ + public Object getHandle() { + return profile; + } + + /** + * Retrieve the UUID of the player. + * @return The UUID of the player, or NULL if not computed. + */ + public String getId() { + return profile.getId(); + } + + /** + * Retrieve the name of the player. + * @return The player name. + */ + public String getName() { + return profile.getName(); + } + + /** + * Construct a new game profile with the same ID, but different id. + * @param name - the new name of the profile to create. + * @return The new game profile. + */ + public WrappedGameProfile withName(String name) { + return new WrappedGameProfile(getId(), name); + } + + /** + * Construct a new game profile with the same name, but different id. + * @param id - the new id of the profile to create. + * @return The new game profile. + */ + public WrappedGameProfile withId(String id) { + return new WrappedGameProfile(id, getName()); + } + + /** + * Determine if the game profile contains both an UUID and a name. + * @return TRUE if it does, FALSE otherwise. + */ + public boolean isComplete() { + return profile.isComplete(); + } + + @Override + public int hashCode() { + return profile.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + + if (obj instanceof WrappedGameProfile) { + WrappedGameProfile other = (WrappedGameProfile) obj; + return profile.equals(other.profile); + } + return false; + } +} diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java index 405d2d54..1738f471 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java @@ -52,6 +52,7 @@ import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.comphenix.protocol.wrappers.WrappedWatchableObject; import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtFactory; @@ -320,6 +321,15 @@ public class PacketContainerTest { assertEquals(list, watchableAccessor.read(0)); } + @Test + public void testGameProfiles() { + PacketContainer spawnEntity = new PacketContainer(PacketType.Play.Server.NAMED_ENTITY_SPAWN); + WrappedGameProfile profile = new WrappedGameProfile("id", "name"); + spawnEntity.getGameProfiles().write(0, profile); + + assertEquals(profile, spawnEntity.getGameProfiles().read(0)); + } + @Test public void testSerialization() { PacketContainer chat = new PacketContainer(PacketType.Play.Client.CHAT); diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java index ab891d21..47317ed6 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.*; import net.minecraft.server.v1_7_R1.NBTCompressedStreamTools; import net.minecraft.util.com.google.common.collect.Maps; +import net.minecraft.util.com.mojang.authlib.GameProfile; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -27,7 +28,7 @@ public class MinecraftReflectionTest { public static void undoMocking() { MinecraftReflection.minecraftPackage = null; } - + @Test public void testNbtStreamTools() { assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());