From 513a83c4b0f2762409406cd21c8d03316a66caaa Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Sat, 12 Mar 2016 15:35:34 -0500 Subject: [PATCH] Fix block positions in watchers and issues with components Fixes #170 --- .../wrappers/WrappedChatComponent.java | 32 +++++++-- .../protocol/wrappers/WrappedDataWatcher.java | 69 +++++++++++++++++-- .../protocol/events/PacketContainerTest.java | 33 +++++---- .../wrappers/WrappedChatComponentTest.java | 5 +- .../wrappers/WrappedDataWatcherTest.java | 17 +++++ 5 files changed, 133 insertions(+), 23 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java index f359c3bc..66ab83bb 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedChatComponent.java @@ -1,5 +1,8 @@ package com.comphenix.protocol.wrappers; +import java.lang.reflect.Method; +import java.util.List; + import org.bukkit.ChatColor; import com.comphenix.protocol.reflect.FuzzyReflection; @@ -27,8 +30,7 @@ public class WrappedChatComponent extends AbstractWrapper { // Retrieve the correct methods SERIALIZE_COMPONENT = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("serialize", /* a */ String.class, new Class[] { COMPONENT })); - DESERIALIZE_COMPONENT = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("deserialize", /* a */ - COMPONENT, new Class[] { String.class })); + DESERIALIZE_COMPONENT = findDeserialize(fuzzy); // Get a component from a standard Minecraft message CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class); @@ -36,6 +38,23 @@ public class WrappedChatComponent extends AbstractWrapper { // And the component text constructor CONSTRUCT_TEXT_COMPONENT = Accessors.getConstructorAccessor(MinecraftReflection.getChatComponentTextClass(), String.class); } + + private static MethodAccessor findDeserialize(FuzzyReflection fuzzy) { + List methods = fuzzy.getMethodListByParameters(COMPONENT, new Class[] { String.class }); + if (methods.isEmpty()) { + throw new IllegalArgumentException("Unable to find deserialize method in " + fuzzy.getSource().getName()); + } + + // Try to find b, we want leniency + for (Method method : methods) { + if (method.getName().equals("b")) { + return Accessors.getMethodAccessor(method); + } + } + + // Oh well + return Accessors.getMethodAccessor(methods.get(0)); + } private transient String cache; @@ -89,7 +108,7 @@ public class WrappedChatComponent extends AbstractWrapper { } return result; } - + /** * Retrieve a copy of this component as a JSON string. *

@@ -134,4 +153,9 @@ public class WrappedChatComponent extends AbstractWrapper { public int hashCode() { return handle.hashCode(); } -} + + @Override + public String toString() { + return "WrappedChatComponent[json=" + getJson() + "]"; + } +} \ No newline at end of file diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java index b42f2bf8..94e3cd16 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedDataWatcher.java @@ -22,7 +22,6 @@ import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -646,12 +645,28 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable + *

  • Byte
  • + *
  • Integer
  • + *
  • Float
  • + *
  • String
  • + *
  • IChatBaseComponent
  • + *
  • Optional<ItemStack>
  • + *
  • Optional<IBlockData>
  • + *
  • Boolean
  • + *
  • Vector3f
  • + *
  • BlockPosition
  • + *
  • Optional<BlockPosition>
  • + *
  • EnumDirection
  • + *
  • Optional<UUID>
  • + * + * * @author dmulloy2 */ public static class Registry { private static boolean INITIALIZED = false; - private static Map, Serializer> REGISTRY = new HashMap<>(); + private static List REGISTRY = new ArrayList<>(); /** * Gets the serializer associated with a given class.
    @@ -660,11 +675,53 @@ public class WrappedDataWatcher extends AbstractWrapper implements IterableNote: If {@link Serializer#isOptional() the serializer is optional}, + * values must be wrapped in an {@link Optional}.

    + * + *

    If there are multiple serializers for a given class (i.e. BlockPosition), + * you should use {@link #get(Class, boolean)} for more precision.

    + * + * @param clazz Class to find serializer for + * @return The serializer, or null if none exists + */ public static Serializer get(Class clazz) { Validate.notNull("Class cannot be null!"); initialize(); - return REGISTRY.get(clazz); + for (Serializer serializer : REGISTRY) { + if (serializer.getType().equals(clazz)) { + return serializer; + } + } + + return null; + } + + /** + * Gets the first serializer associated with a given class and optional state. + * + *

    Note: If the serializer is optional, values must be wrapped in an {@link Optional} + * + * @param clazz Class to find serializer for + * @param optional Optional state + * @return The serializer, or null if none exists + */ + public static Serializer get(Class clazz, boolean optional) { + Validate.notNull(clazz, "Class cannot be null!"); + initialize(); + + for (Serializer serializer : REGISTRY) { + if (serializer.getType().equals(clazz) + && serializer.isOptional() == optional) { + return serializer; + } + } + + return null; } /** @@ -676,7 +733,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable integers = mapChunkBulk.getIntegerArrays(); int[] testArray = new int[] { 1, 2, 3 }; @@ -195,7 +198,7 @@ public class PacketContainerTest { integers.write(0, testArray); assertArrayEquals(testArray, integers.read(0)); - }*/ + } @Test public void testGetItemModifier() { @@ -447,24 +450,30 @@ public class PacketContainerTest { assertEquals(material, read.getType()); } - /*@Test + @Test @SuppressWarnings("deprecation") public void testPotionEffect() { PotionEffect effect = new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 20 * 60, 1); - MobEffect mobEffect = new MobEffect(effect.getType().getId(), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), + MobEffect mobEffect = new MobEffect(MobEffectList.fromId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()); - + int entityId = 42; + // The constructor we want to call PacketConstructor creator = PacketConstructor.DEFAULT.withPacket( PacketType.Play.Server.ENTITY_EFFECT, new Class[] { int.class, MobEffect.class }); - PacketContainer packet = creator.createPacket(1, mobEffect); + PacketContainer packet = creator.createPacket(entityId, mobEffect); - assertEquals(1, (int) packet.getIntegers().read(0)); + assertEquals(entityId, (int) packet.getIntegers().read(0)); assertEquals(effect.getType().getId(), (byte) packet.getBytes().read(0)); assertEquals(effect.getAmplifier(), (byte) packet.getBytes().read(1)); assertEquals(effect.getDuration(), (int) packet.getIntegers().read(1)); - assertEquals(effect.hasParticles(), packet.getBytes().read(2) == (effect.hasParticles() ? 1 : 0)); - }*/ + + int e = 0; + if (effect.isAmbient()) e |= 1; + if (effect.hasParticles()) e |= 2; + + assertEquals(e, (byte) packet.getBytes().read(2)); + } private static final List BLACKLISTED = Util.asList( PacketType.Play.Client.CUSTOM_PAYLOAD, PacketType.Play.Server.CUSTOM_PAYLOAD, diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChatComponentTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChatComponentTest.java index c71ebd33..b5e1233b 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChatComponentTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedChatComponentTest.java @@ -1,5 +1,6 @@ package com.comphenix.protocol.wrappers; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.BeforeClass; @@ -18,7 +19,9 @@ public class WrappedChatComponentTest { public void testText() { WrappedChatComponent test = WrappedChatComponent.fromText("Hello."); String json = test.getJson(); - assertNotNull(json); + + WrappedChatComponent clone = WrappedChatComponent.fromJson(json); + assertEquals(json, clone.getJson()); } } diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java index c8aa21e5..38fc63e1 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/WrappedDataWatcherTest.java @@ -4,10 +4,17 @@ package com.comphenix.protocol.wrappers; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; + +import java.util.UUID; + import net.minecraft.server.v1_9_R1.DataWatcher; import net.minecraft.server.v1_9_R1.Entity; import net.minecraft.server.v1_9_R1.EntityLightning; +import net.minecraft.server.v1_9_R1.ItemStack; import org.junit.BeforeClass; import org.junit.Test; @@ -71,4 +78,14 @@ public class WrappedDataWatcherTest { DataWatcher handle = entity.getDataWatcher(); return new WrappedDataWatcher(handle); } + + @Test + public void testSerializers() { + Serializer blockPos = Registry.get(net.minecraft.server.v1_9_R1.BlockPosition.class, false); + Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_9_R1.BlockPosition.class, true); + assertNotSame(blockPos, optionalBlockPos); + + assertNull(Registry.get(ItemStack.class, false)); + assertNotNull(Registry.get(UUID.class, true)); + } } \ No newline at end of file