From 17a5b06577573a7c917181d532f1eb22d96fb0f9 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Tue, 10 Dec 2013 22:35:29 +0100 Subject: [PATCH] Adding a new ChunkCoordIntPair wrapper. --- .../protocol/events/PacketContainer.java | 12 ++ .../protocol/utility/MinecraftReflection.java | 38 ++++++ .../protocol/wrappers/ChunkCoordIntPair.java | 121 ++++++++++++++++++ .../utility/MinecraftReflectionTest.java | 6 + .../wrappers/ChunkCoordIntPairTest.java | 31 +++++ 5 files changed, 208 insertions(+) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkCoordIntPair.java create mode 100644 ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/ChunkCoordIntPairTest.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 8caa7e11..78a0604b 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -67,6 +67,7 @@ import com.comphenix.protocol.utility.MinecraftMethods; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.StreamSerializer; import com.comphenix.protocol.wrappers.BukkitConverters; +import com.comphenix.protocol.wrappers.ChunkCoordIntPair; import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.EnumWrappers; import com.comphenix.protocol.wrappers.EnumWrappers.Difficulty; @@ -426,6 +427,17 @@ public class PacketContainer implements Serializable { ChunkPosition.getConverter()); } + /** + * Retrieves a read/write structure for wrapped ChunkCoordIntPairs. + * @return A modifier for ChunkCoordIntPair. + */ + public StructureModifier getChunkCoordIntPairs() { + // Allow access to the NBT class in packet 130 + return structureModifier.withType( + MinecraftReflection.getChunkCoordIntPair(), + ChunkCoordIntPair.getConverter()); + } + /** * Retrieves a read/write structure for NBT classes. * @return A modifier for NBT classes. 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 7a56f505..629ca2b5 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -388,6 +388,15 @@ public class MinecraftReflection { return obj != null && getChunkPositionClass().isAssignableFrom(obj.getClass()); } + /** + * Determine if the given object is an NMS ChunkCoordIntPar. + * @param obj - the object. + * @return TRUE if it can, FALSE otherwise. + */ + public static boolean isChunkCoordIntPair(Object obj) { + return obj != null && getChunkCoordIntPair().isAssignableFrom(obj.getClass()); + } + /** * Determine if a given object is a ChunkCoordinate. * @param obj - the object to test. @@ -1093,6 +1102,35 @@ public class MinecraftReflection { } } + /** + * Retrieve the ChunkCoordIntPair class. + * @return The ChunkCoordIntPair class. + */ + public static Class getChunkCoordIntPair() { + if (!isUsingNetty()) + throw new IllegalArgumentException("Not supported on 1.6.4 and older."); + + try { + return getMinecraftClass("ChunkCoordIntPair"); + } catch (RuntimeException e) { + Class packet = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.MULTI_BLOCK_CHANGE); + + AbstractFuzzyMatcher> chunkCoordIntContract = FuzzyClassContract.newBuilder(). + field(FuzzyFieldContract.newBuilder(). + typeDerivedOf(int.class)). + field(FuzzyFieldContract.newBuilder(). + typeDerivedOf(int.class)). + method(FuzzyMethodContract.newBuilder(). + parameterExactArray(int.class). + returnDerivedOf( getChunkPositionClass() )). + build().and(getMinecraftObjectMatcher()); + + Field field = FuzzyReflection.fromClass(packet, true).getField( + FuzzyFieldContract.matchType(chunkCoordIntContract)); + return setMinecraftClass("ChunkCoordIntPair", field.getType()); + } + } + /** * Retrieve the WatchableObject class. * @return The WatchableObject class. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkCoordIntPair.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkCoordIntPair.java new file mode 100644 index 00000000..0b6e3628 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/ChunkCoordIntPair.java @@ -0,0 +1,121 @@ +package com.comphenix.protocol.wrappers; + +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; +import com.comphenix.protocol.reflect.accessors.FieldAccessor; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.google.common.base.Objects; + +/** + * Represents a ChunkCoordIntPair. + * @author Kristian + */ +public class ChunkCoordIntPair { + private static Class COORD_PAIR_CLASS = MinecraftReflection.getChunkCoordIntPair(); + private static ConstructorAccessor COORD_CONSTRUCTOR; + private static FieldAccessor COORD_X; + private static FieldAccessor COORD_Z; + + // Use protected members, like Bukkit + protected final int chunkX; + protected final int chunkZ; + + /** + * Construct a new chunk coord int pair. + * @param x - the x index of the chunk. + * @param z - the z index of the chunk. + */ + public ChunkCoordIntPair(int x, int z) { + this.chunkX = x; + this.chunkZ = z; + } + + /** + * Retrieve the equivalent chunk position. + * @param y - the y position. + * @return The chunk position. + */ + public ChunkPosition getPosition(int y) { + return new ChunkPosition((chunkX << 4) + 8, y, (chunkZ << 4) + 8); + } + + /** + * Retrieve the chunk index in the x-dimension. + *

+ * This is the number of adjacent chunks to (0, 0), not a block coordinate. + * @return The x chunk index. + */ + public int getChunkX() { + return chunkX; + } + + /** + * Retrieve the chunk index in the z-dimension. + *

+ * This is the number of adjacent chunks to (0, 0), not a block coordinate. + * @return The z chunk index. + */ + public int getChunkZ() { + return chunkZ; + } + + /** + * Used to convert between NMS ChunkPosition and the wrapper instance. + * @return A new converter. + */ + public static EquivalentConverter getConverter() { + return new EquivalentConverter() { + @Override + public Object getGeneric(Class genericType, ChunkCoordIntPair specific) { + if (COORD_CONSTRUCTOR == null) { + COORD_CONSTRUCTOR = Accessors.getConstructorAccessor(COORD_PAIR_CLASS, int.class, int.class); + } + + return COORD_CONSTRUCTOR.invoke(specific.chunkX, specific.chunkZ); + } + + @Override + public ChunkCoordIntPair getSpecific(Object generic) { + if (MinecraftReflection.isChunkCoordIntPair(generic)) { + if (COORD_X == null || COORD_Z == null) { + FieldAccessor[] ints = Accessors.getFieldAccessorArray(COORD_PAIR_CLASS, int.class, true); + COORD_X = ints[0]; + COORD_Z = ints[1]; + } + return new ChunkCoordIntPair((Integer) COORD_X.get(generic), (Integer) COORD_Z.get(generic)); + } + + // Otherwise, return NULL + return null; + } + + @Override + public Class getSpecificType() { + return ChunkCoordIntPair.class; + } + }; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + + // Only compare objects of similar type + if (obj instanceof ChunkCoordIntPair) { + ChunkCoordIntPair other = (ChunkCoordIntPair) obj; + return chunkX == other.chunkX && chunkZ == other.chunkZ; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(chunkX, chunkZ); + } + + @Override + public String toString() { + return "ChunkCoordIntPair [x=" + chunkX + ", z=" + chunkZ + "]"; + } +} 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 a82c8d3a..457c4ed3 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java @@ -3,6 +3,7 @@ package com.comphenix.protocol.utility; import static org.junit.Assert.*; import net.minecraft.server.v1_7_R1.ChatSerializer; +import net.minecraft.server.v1_7_R1.ChunkCoordIntPair; import net.minecraft.server.v1_7_R1.IChatBaseComponent; import net.minecraft.server.v1_7_R1.NBTCompressedStreamTools; import net.minecraft.server.v1_7_R1.ServerPing; @@ -62,4 +63,9 @@ public class MinecraftReflectionTest { public void testServerPingServerData() { assertEquals(ServerPingServerData.class, MinecraftReflection.getServerPingServerDataClass()); } + + @Test + public void testChunkCoordIntPair() { + assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair()); + } } diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/ChunkCoordIntPairTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/ChunkCoordIntPairTest.java new file mode 100644 index 00000000..bba5abc0 --- /dev/null +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/wrappers/ChunkCoordIntPairTest.java @@ -0,0 +1,31 @@ +package com.comphenix.protocol.wrappers; + +import static org.junit.Assert.*; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.comphenix.protocol.BukkitInitialization; + +public class ChunkCoordIntPairTest { + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + BukkitInitialization.initializePackage(); + } + + @Test + public void test() { + net.minecraft.server.v1_7_R1.ChunkCoordIntPair pair = new net.minecraft.server.v1_7_R1.ChunkCoordIntPair(1, 2); + ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair); + + assertEquals(1, specific.getChunkX()); + assertEquals(2, specific.getChunkZ()); + + net.minecraft.server.v1_7_R1.ChunkCoordIntPair roundtrip = + (net.minecraft.server.v1_7_R1.ChunkCoordIntPair) ChunkCoordIntPair.getConverter(). + getGeneric(net.minecraft.server.v1_7_R1.ChunkCoordIntPair.class, specific); + + assertEquals(1, roundtrip.x); + assertEquals(2, roundtrip.z); + } +}