From 4259a8674008336c493cd46dccf609a2c34e857e Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Mon, 3 Mar 2014 23:11:05 +0100 Subject: [PATCH] Optimize lookup of getBukkitEntity. --- .../protocol/utility/MinecraftReflection.java | 16 ++++++++-- .../protocol/SimpleCraftBukkitITCase.java | 26 ++++++++++------ .../utility/MinecraftReflectionTest.java | 31 ++++++++++++++++++- 3 files changed, 61 insertions(+), 12 deletions(-) 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 da5996e4..ef837f64 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -56,6 +56,7 @@ import com.comphenix.protocol.reflect.ClassAnalyser; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod; import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor; import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor; import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher; @@ -69,6 +70,9 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.comphenix.protocol.wrappers.nbt.NbtType; import com.google.common.base.Joiner; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; /** * Methods and constants specifically used in conjuction with reflecting Minecraft object. @@ -141,6 +145,14 @@ public class MinecraftReflection { // net.minecraft.server private static Class itemStackArrayClass; + // Cache of getBukkitEntity + private static Cache, MethodAccessor> getBukkitEntityCache = CacheBuilder.newBuilder().build( + new CacheLoader, MethodAccessor>() { + public MethodAccessor load(java.lang.Class paramK) throws Exception { + return Accessors.getMethodAccessor(paramK, "getBukkitEntity"); + }; + }); + // The current class source private static ClassSource classSource; @@ -367,9 +379,9 @@ public class MinecraftReflection { // We will have to do this dynamically, unfortunately try { - return nmsObject.getClass().getMethod("getBukkitEntity").invoke(nmsObject); + return getBukkitEntityCache.apply(nmsObject.getClass()).invoke(nmsObject); } catch (Exception e) { - throw new RuntimeException("Cannot get Bukkit entity from " + nmsObject, e); + throw new IllegalArgumentException("Cannot get Bukkit entity from " + nmsObject, e); } } diff --git a/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleCraftBukkitITCase.java b/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleCraftBukkitITCase.java index 6646024a..f93cf690 100644 --- a/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleCraftBukkitITCase.java +++ b/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleCraftBukkitITCase.java @@ -106,24 +106,32 @@ public class SimpleCraftBukkitITCase { @SuppressWarnings("deprecation") private static void setupPlugins() throws IOException { File pluginDirectory = new File("plugins/"); + File srcDirectory = new File("../"); File bestFile = null; int bestLength = Integer.MAX_VALUE; + + for (File file : srcDirectory.listFiles()) { + String name = file.getName(); + + if (file.isFile() && name.startsWith("ProtocolLib") && name.length() < bestLength) { + bestLength = name.length(); + bestFile = file; + } + } + + if (bestFile == null) { + throw new IllegalStateException("Cannot find ProtocolLib in " + srcDirectory); + } // Copy the ProtocolLib plugin to the server if (pluginDirectory.exists()) { Files.deleteDirectoryContents(pluginDirectory); } - - for (File file : new File("../").listFiles()) { - String name = file.getName(); - if (name.startsWith("ProtocolLib") && name.length() < bestLength) { - bestLength = name.length(); - bestFile = file; - } - } pluginDirectory.mkdirs(); - Files.copy(bestFile, new File(pluginDirectory, bestFile.getName())); + + File destination = new File(pluginDirectory, bestFile.getName()).getAbsoluteFile(); + Files.copy(bestFile, destination); } /** 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 43aceb7f..23ea2499 100644 --- a/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTest.java @@ -1,6 +1,7 @@ package com.comphenix.protocol.utility; import static org.junit.Assert.*; +import static org.mockito.Mockito.*; import net.minecraft.server.v1_7_R1.ChatComponentText; import net.minecraft.server.v1_7_R1.ChatSerializer; @@ -11,6 +12,8 @@ import net.minecraft.server.v1_7_R1.ServerPing; import net.minecraft.server.v1_7_R1.ServerPingPlayerSample; import net.minecraft.server.v1_7_R1.ServerPingServerData; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -19,6 +22,15 @@ import com.comphenix.protocol.BukkitInitialization; import com.google.common.collect.Maps; public class MinecraftReflectionTest { + // Mocking objects + private interface FakeEntity { + public Entity getBukkitEntity(); + } + + private interface FakeBlock { + public Block getBukkitEntity(); + } + @BeforeClass public static void initializeReflection() throws IllegalAccessException { BukkitInitialization.initializePackage(); @@ -32,7 +44,24 @@ public class MinecraftReflectionTest { @AfterClass public static void undoMocking() { - MinecraftReflection.minecraftPackage = null; + // NOP + } + + @Test + public void testBukkitMethod() { + FakeEntity entity = mock(FakeEntity.class); + FakeBlock block = mock(FakeBlock.class); + + MinecraftReflection.getBukkitEntity(entity); + MinecraftReflection.getBukkitEntity(block); + + verify(entity, times(1)).getBukkitEntity(); + verify(block, times(1)).getBukkitEntity(); + } + + @Test(expected = IllegalArgumentException.class) + public void testIllegalClass() { + MinecraftReflection.getBukkitEntity("Hello"); } @Test