Use reflection for the attribute remover. Use ItemFlag for 1.8.3+

(better performance)
This commit is contained in:
filoghost 2015-05-04 15:10:52 +02:00
parent 3018b440de
commit 67103162a9
14 changed files with 167 additions and 288 deletions

View File

@ -30,7 +30,6 @@ import com.gmail.filoghost.chestcommands.listener.InventoryListener;
import com.gmail.filoghost.chestcommands.listener.JoinListener;
import com.gmail.filoghost.chestcommands.listener.SignListener;
import com.gmail.filoghost.chestcommands.nms.AttributeRemover;
import com.gmail.filoghost.chestcommands.nms.Fallback;
import com.gmail.filoghost.chestcommands.serializer.CommandSerializer;
import com.gmail.filoghost.chestcommands.serializer.MenuSerializer;
import com.gmail.filoghost.chestcommands.task.ErrorLoggerTask;
@ -84,14 +83,7 @@ public class ChestCommands extends JavaPlugin {
getLogger().info("Hooked PlayerPoints");
}
String version = Utils.getBukkitVersion();
try {
Class<?> clazz = Class.forName("com.gmail.filoghost.chestcommands.nms." + version);
attributeRemover = (AttributeRemover) clazz.newInstance();
} catch (Exception e) {
attributeRemover = new Fallback();
getLogger().info("Could not find a compatible Attribute Remover for this server version. Attributes will show up on items.");
}
AttributeRemover.setup();
if (settings.update_notifications) {
new SimpleUpdater(this, 56919).checkForUpdates(new ResponseHandler() {

View File

@ -6,8 +6,8 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import com.gmail.filoghost.chestcommands.ChestCommands;
import com.gmail.filoghost.chestcommands.internal.MenuInventoryHolder;
import com.gmail.filoghost.chestcommands.nms.AttributeRemover;
import com.gmail.filoghost.chestcommands.util.Utils;
import com.gmail.filoghost.chestcommands.util.Validate;
@ -79,7 +79,7 @@ public class IconMenu {
for (int i = 0; i < icons.length; i++) {
if (icons[i] != null) {
inventory.setItem(i, ChestCommands.getAttributeRemover().removeAttributes(icons[i].createItemstack(player)));
inventory.setItem(i, AttributeRemover.hideAttributes(icons[i].createItemstack(player)));
}
}

View File

@ -1,21 +1,46 @@
package com.gmail.filoghost.chestcommands.internal;
import java.lang.reflect.Method;
import java.util.Collection;
import org.bukkit.Bukkit;
public class CachedGetters {
private static long lastOnlinePlayersRefresh;
private static int onlinePlayers;
private static Method getOnlinePlayersMethod;
static {
try {
getOnlinePlayersMethod = Bukkit.class.getMethod("getOnlinePlayers");
} catch (Exception ex) { }
}
public static int getOnlinePlayers() {
long now = System.currentTimeMillis();
if (lastOnlinePlayersRefresh == 0 || now - lastOnlinePlayersRefresh > 1000) {
// getOnlinePlayers() could be expensive if called frequently
lastOnlinePlayersRefresh = now;
onlinePlayers = Bukkit.getOnlinePlayers().length;
try {
onlinePlayers = count(getOnlinePlayersMethod.invoke(null));
} catch (Exception e) {
onlinePlayers = -1;
}
}
return onlinePlayers;
}
private static int count(Object o) {
if (o.getClass().isArray()) {
return ((Object[]) o).length;
} else if (o instanceof Collection<?>) {
return ((Collection<?>) o).size();
} else {
return -1;
}
}
}

View File

@ -15,6 +15,7 @@ import com.gmail.filoghost.chestcommands.Permissions;
import com.gmail.filoghost.chestcommands.api.IconMenu;
import com.gmail.filoghost.chestcommands.internal.icon.ExtendedIcon;
import com.gmail.filoghost.chestcommands.internal.icon.IconCommand;
import com.gmail.filoghost.chestcommands.nms.AttributeRemover;
public class ExtendedIconMenu extends IconMenu {
@ -72,7 +73,7 @@ public class ExtendedIconMenu extends IconMenu {
continue;
}
inventory.setItem(i, ChestCommands.getAttributeRemover().removeAttributes(icons[i].createItemstack(player)));
inventory.setItem(i, AttributeRemover.hideAttributes(icons[i].createItemstack(player)));
}
}
@ -96,12 +97,12 @@ public class ExtendedIconMenu extends IconMenu {
if (extIcon.canViewIcon(player)) {
if (inventory.getItem(i) == null) {
ItemStack updatedIcon = ChestCommands.getAttributeRemover().removeAttributes(extIcon.createItemstack(player));
ItemStack updatedIcon = extIcon.createItemstack(player);
inventory.setItem(i, updatedIcon);
}
// Performance, only update name and lore.
ItemStack inventoryItem = inventory.getItem(i);
ItemStack inventoryItem = AttributeRemover.hideAttributes(inventory.getItem(i));
ItemMeta meta = inventoryItem.getItemMeta();
meta.setDisplayName(extIcon.calculateName(player));
meta.setLore(extIcon.calculateLore(player));

View File

@ -1,9 +1,122 @@
package com.gmail.filoghost.chestcommands.nms;
import java.lang.reflect.Method;
import java.util.Collection;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public interface AttributeRemover {
import com.gmail.filoghost.chestcommands.util.Utils;
public ItemStack removeAttributes(ItemStack item);
public class AttributeRemover {
private static boolean useItemFlags;
private static boolean useReflection;
// Reflection stuff
private static Class<?> nbtTagCompoundClass;
private static Class<?> nbtTagListClass;
private static Class<?> nmsItemstackClass;
private static Method asNmsCopyMethod; // static
private static Method asCraftMirrorMethod; // static
private static Method hasTagMethod;
private static Method getTagMethod;
private static Method setTagMethod;
private static Method nbtSetMethod;
public static boolean setup() {
if (Utils.isClassLoaded("org.bukkit.inventory.ItemFlag")) {
// We can use the new Bukkit API (1.8.3+)
useItemFlags = true;
} else {
try {
// Try to get the NMS methods and classes
nbtTagCompoundClass = getNmsClass("NBTTagCompound");
nbtTagListClass = getNmsClass("NBTTagList");
nmsItemstackClass = getNmsClass("ItemStack");
asNmsCopyMethod = getObcClass("inventory.CraftItemStack").getMethod("asNMSCopy", ItemStack.class);
asCraftMirrorMethod = getObcClass("inventory.CraftItemStack").getMethod("asCraftMirror", nmsItemstackClass);
hasTagMethod = nmsItemstackClass.getMethod("hasTag");
getTagMethod = nmsItemstackClass.getMethod("getTag");
setTagMethod = nmsItemstackClass.getMethod("setTag", nbtTagCompoundClass);
nbtSetMethod = nbtTagCompoundClass.getMethod("set", String.class, getNmsClass("NBTBase"));
useReflection = true;
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
private static Class<?> getNmsClass(String name) throws ClassNotFoundException {
return Class.forName("net.minecraft.server." + Utils.getBukkitVersion() + "." + name);
}
private static Class<?> getObcClass(String name) throws ClassNotFoundException {
return Class.forName("org.bukkit.craftbukkit." + Utils.getBukkitVersion() + "." + name);
}
public static ItemStack hideAttributes(ItemStack item) {
if (item == null) {
return null;
}
if (useItemFlags) {
ItemMeta meta = item.getItemMeta();
if (isNullOrEmpty(meta.getItemFlags())) {
// Add them only if necessary
meta.addItemFlags(ItemFlag.values());
item.setItemMeta(meta);
}
return item;
} else if (useReflection) {
try {
Object nmsItemstack = asNmsCopyMethod.invoke(null, item);
if (nmsItemstack == null) {
return item;
}
Object nbtCompound;
if ((Boolean) hasTagMethod.invoke(nmsItemstack)) {
nbtCompound = getTagMethod.invoke(nmsItemstack);
} else {
nbtCompound = nbtTagCompoundClass.newInstance();
setTagMethod.invoke(nmsItemstack, nbtCompound);
}
if (nbtCompound == null) {
return item;
}
Object nbtList = nbtTagListClass.newInstance();
nbtSetMethod.invoke(nbtCompound, "AttributeModifiers", nbtList);
return (ItemStack) asCraftMirrorMethod.invoke(null, nmsItemstack);
} catch (Exception e) { }
}
// On failure
return item;
}
private static boolean isNullOrEmpty(Collection<?> coll) {
return coll == null || coll.isEmpty();
}
}

View File

@ -1,12 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import org.bukkit.inventory.ItemStack;
public class Fallback implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
return item;
}
}

View File

@ -1,37 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_6_R2.NBTTagCompound;
import net.minecraft.server.v1_6_R2.NBTTagList;
import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_6_R2 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_6_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()){
tag = new NBTTagCompound();
nmsStack.setTag(tag);
}
else {
tag = nmsStack.getTag();
}
NBTTagList am = new NBTTagList();
tag.set("AttributeModifiers", am);
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -1,37 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.NBTTagList;
import org.bukkit.craftbukkit.v1_6_R3.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_6_R3 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_6_R3.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()){
tag = new NBTTagCompound();
nmsStack.setTag(tag);
}
else {
tag = nmsStack.getTag();
}
NBTTagList am = new NBTTagList();
tag.set("AttributeModifiers", am);
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -1,37 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.NBTTagList;
import org.bukkit.craftbukkit.v1_7_R1.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_7_R1 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_7_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()){
tag = new NBTTagCompound();
nmsStack.setTag(tag);
}
else {
tag = nmsStack.getTag();
}
NBTTagList am = new NBTTagList();
tag.set("AttributeModifiers", am);
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -1,37 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.NBTTagList;
import org.bukkit.craftbukkit.v1_7_R2.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_7_R2 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_7_R2.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()){
tag = new NBTTagCompound();
nmsStack.setTag(tag);
}
else {
tag = nmsStack.getTag();
}
NBTTagList am = new NBTTagList();
tag.set("AttributeModifiers", am);
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -1,37 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.NBTTagList;
import org.bukkit.craftbukkit.v1_7_R3.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_7_R3 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_7_R3.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()){
tag = new NBTTagCompound();
nmsStack.setTag(tag);
}
else {
tag = nmsStack.getTag();
}
NBTTagList am = new NBTTagList();
tag.set("AttributeModifiers", am);
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -1,37 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_7_R4.NBTTagCompound;
import net.minecraft.server.v1_7_R4.NBTTagList;
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_7_R4 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_7_R4.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()){
tag = new NBTTagCompound();
nmsStack.setTag(tag);
}
else {
tag = nmsStack.getTag();
}
NBTTagList am = new NBTTagList();
tag.set("AttributeModifiers", am);
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -1,34 +0,0 @@
package com.gmail.filoghost.chestcommands.nms;
import net.minecraft.server.v1_8_R1.NBTTagCompound;
import net.minecraft.server.v1_8_R1.NBTTagInt;
import org.bukkit.craftbukkit.v1_8_R1.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
public class v1_8_R1 implements AttributeRemover {
@Override
public ItemStack removeAttributes(ItemStack item) {
if(item == null) {
return item;
}
net.minecraft.server.v1_8_R1.ItemStack nmsStack = CraftItemStack.asNMSCopy(item);
if (nmsStack == null) return item;
NBTTagCompound tag;
if (!nmsStack.hasTag()) {
tag = new NBTTagCompound();
nmsStack.setTag(tag);
} else {
tag = nmsStack.getTag();
}
tag.set("HideFlags", new NBTTagInt(Integer.MAX_VALUE));
nmsStack.setTag(tag);
return CraftItemStack.asCraftMirror(nmsStack);
}
}

View File

@ -34,6 +34,7 @@ public class Utils {
// Default material names are ugly.
private static Map<String, Material> materialMap = newHashMap();
static {
for (Material mat : Material.values()) {
materialMap.put(StringUtils.stripChars(mat.toString(), "_").toLowerCase(), mat);
@ -98,9 +99,15 @@ public class Utils {
}
}
private static String bukkitVersion;
public static String getBukkitVersion() {
if (bukkitVersion == null) {
String packageName = Bukkit.getServer().getClass().getPackage().getName();
return packageName.substring(packageName.lastIndexOf('.') + 1);
bukkitVersion = packageName.substring(packageName.lastIndexOf('.') + 1);
}
return bukkitVersion;
}
public static String colorizeName(String input) {
@ -326,4 +333,13 @@ public class Utils {
return builder.toString();
}
public static boolean isClassLoaded(String name) {
try {
Class.forName(name);
return true;
} catch (Exception e) {
return false;
}
}
}