Optimize lookup of getBukkitEntity.

This commit is contained in:
Kristian S. Stangeland 2014-03-03 23:11:05 +01:00
parent b84aace585
commit 4259a86740
3 changed files with 61 additions and 12 deletions

View File

@ -56,6 +56,7 @@ import com.comphenix.protocol.reflect.ClassAnalyser;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod; import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod;
import com.comphenix.protocol.reflect.accessors.Accessors; 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.EmptyClassVisitor;
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor; import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher; 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.NbtFactory;
import com.comphenix.protocol.wrappers.nbt.NbtType; import com.comphenix.protocol.wrappers.nbt.NbtType;
import com.google.common.base.Joiner; 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. * Methods and constants specifically used in conjuction with reflecting Minecraft object.
@ -141,6 +145,14 @@ public class MinecraftReflection {
// net.minecraft.server // net.minecraft.server
private static Class<?> itemStackArrayClass; private static Class<?> itemStackArrayClass;
// Cache of getBukkitEntity
private static Cache<Class<?>, MethodAccessor> getBukkitEntityCache = CacheBuilder.newBuilder().build(
new CacheLoader<Class<?>, MethodAccessor>() {
public MethodAccessor load(java.lang.Class<?> paramK) throws Exception {
return Accessors.getMethodAccessor(paramK, "getBukkitEntity");
};
});
// The current class source // The current class source
private static ClassSource classSource; private static ClassSource classSource;
@ -367,9 +379,9 @@ public class MinecraftReflection {
// We will have to do this dynamically, unfortunately // We will have to do this dynamically, unfortunately
try { try {
return nmsObject.getClass().getMethod("getBukkitEntity").invoke(nmsObject); return getBukkitEntityCache.apply(nmsObject.getClass()).invoke(nmsObject);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Cannot get Bukkit entity from " + nmsObject, e); throw new IllegalArgumentException("Cannot get Bukkit entity from " + nmsObject, e);
} }
} }

View File

@ -106,24 +106,32 @@ public class SimpleCraftBukkitITCase {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private static void setupPlugins() throws IOException { private static void setupPlugins() throws IOException {
File pluginDirectory = new File("plugins/"); File pluginDirectory = new File("plugins/");
File srcDirectory = new File("../");
File bestFile = null; File bestFile = null;
int bestLength = Integer.MAX_VALUE; 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 // Copy the ProtocolLib plugin to the server
if (pluginDirectory.exists()) { if (pluginDirectory.exists()) {
Files.deleteDirectoryContents(pluginDirectory); 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(); pluginDirectory.mkdirs();
Files.copy(bestFile, new File(pluginDirectory, bestFile.getName()));
File destination = new File(pluginDirectory, bestFile.getName()).getAbsoluteFile();
Files.copy(bestFile, destination);
} }
/** /**

View File

@ -1,6 +1,7 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import static org.junit.Assert.*; 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.ChatComponentText;
import net.minecraft.server.v1_7_R1.ChatSerializer; 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.ServerPingPlayerSample;
import net.minecraft.server.v1_7_R1.ServerPingServerData; 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.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -19,6 +22,15 @@ import com.comphenix.protocol.BukkitInitialization;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
public class MinecraftReflectionTest { public class MinecraftReflectionTest {
// Mocking objects
private interface FakeEntity {
public Entity getBukkitEntity();
}
private interface FakeBlock {
public Block getBukkitEntity();
}
@BeforeClass @BeforeClass
public static void initializeReflection() throws IllegalAccessException { public static void initializeReflection() throws IllegalAccessException {
BukkitInitialization.initializePackage(); BukkitInitialization.initializePackage();
@ -32,7 +44,24 @@ public class MinecraftReflectionTest {
@AfterClass @AfterClass
public static void undoMocking() { 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 @Test