Merge branch 'master' into 'master'

moved serialization utils to its own class ItemSerializer and cached c+m

See merge request Songoda/UltimateKits!9
This commit is contained in:
Brianna O'Keefe 2018-12-04 02:41:57 +00:00
commit 35ea145ee0
8 changed files with 285 additions and 212 deletions

View File

@ -13,6 +13,7 @@ import com.songoda.ultimatekits.key.Key;
import com.songoda.ultimatekits.key.KeyManager;
import com.songoda.ultimatekits.kit.*;
import com.songoda.ultimatekits.utils.Debugger;
import com.songoda.ultimatekits.utils.ItemSerializer;
import com.songoda.ultimatekits.utils.SettingsManager;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -42,6 +43,8 @@ public class UltimateKits extends JavaPlugin {
private KeyManager keyManager;
private HologramHandler hologramHandler;
private DisplayItemHandler displayItemHandler;
private ItemSerializer itemSerializer;
/**
* Grab instance of UltimateKits
@ -101,6 +104,13 @@ public class UltimateKits extends JavaPlugin {
this.keyManager = new KeyManager();
this.commandManager = new CommandManager(this);
this.hologramHandler = new HologramHandler(this);
try {
this.itemSerializer = new ItemSerializer();
} catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
console.sendMessage(TextComponent.formatText("&cCould not load the serialization class! Please report this error."));
e.printStackTrace();
}
this.loadFromFile();
@ -336,6 +346,7 @@ public class UltimateKits extends JavaPlugin {
public ConfigWrapper getDataFile() {
return dataFile;
}
public SettingsManager getSettingsManager() {
return settingsManager;
@ -348,6 +359,15 @@ public class UltimateKits extends JavaPlugin {
public HologramHandler getHologramHandler() {
return hologramHandler;
}
/**
* Grab instance of the item serializer
*
* @return instance of ItemSerializer
*/
public ItemSerializer getItemSerializer() {
return this.itemSerializer;
}
public References getReferences() {
return references;

View File

@ -53,7 +53,7 @@ public class Convert {
for (String kit : kits) {
List<String> serializedItems = new ArrayList<>();
for (ItemStack item : hook.getItems(kit)) {
serializedItems.add(Methods.serializeItemStackToJson(item));
serializedItems.add(instance.getItemSerializer().serializeItemStackToJson(item));
}
instance.getKitFile().getConfig().set("Kits." + kit + ".items", serializedItems);
instance.getKitFile().getConfig().set("Kits." + kit + ".delay", hook.getDelay(kit));

View File

@ -1,7 +1,7 @@
package com.songoda.ultimatekits.conversion.hooks;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.conversion.Hook;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
@ -15,7 +15,7 @@ public class DefaultDeprecatedHook implements Hook {
for (Kits kit : Kits.values()) {
if (!kit.name().equalsIgnoreCase(kitName)) continue;
for (String string : kit.items) {
items.add(Methods.deserializeItemStack(string));
items.add(UltimateKits.getInstance().getItemSerializer().deserializeItemStack(string));
}
}

View File

@ -1,7 +1,7 @@
package com.songoda.ultimatekits.conversion.hooks;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.conversion.Hook;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
@ -15,7 +15,7 @@ public class DefaultHook implements Hook {
for (Kits kit : Kits.values()) {
if (!kit.name().equalsIgnoreCase(kitName)) continue;
for (String string : kit.items) {
items.add(Methods.deserializeItemStackFromJson(string));
items.add(UltimateKits.getInstance().getItemSerializer().deserializeItemStackFromJson(string));
}
}

View File

@ -7,7 +7,6 @@ import com.songoda.ultimatekits.kit.type.KitContent;
import com.songoda.ultimatekits.kit.type.KitContentCommand;
import com.songoda.ultimatekits.kit.type.KitContentEconomy;
import com.songoda.ultimatekits.kit.type.KitContentItem;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@ -33,7 +32,7 @@ public class KitItem {
} else if (line.startsWith("/")) {
this.content = new KitContentCommand(line.substring(1));
} else {
this.content = new KitContentItem(Methods.deserializeLegacyItemStack(line));
this.content = new KitContentItem(UltimateKits.getInstance().getItemSerializer().deserializeLegacyItemStack(line));
}
}

View File

@ -1,5 +1,6 @@
package com.songoda.ultimatekits.kit.type;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.inventory.ItemStack;
@ -20,7 +21,7 @@ public class KitContentItem implements KitContent {
@Override
public String getSerialized() {
if (serialized != null) return serialized;
serialized = Methods.serializeItemStackToJson(itemStack);
serialized = UltimateKits.getInstance().getItemSerializer().serializeItemStackToJson(itemStack);
return serialized;
}

View File

@ -0,0 +1,257 @@
package com.songoda.ultimatekits.utils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import com.songoda.arconix.plugin.Arconix;
import com.songoda.ultimatekits.UltimateKits;
public class ItemSerializer {
// classes needed for reflections
private Class<?> classMojangsonParser = Class.forName(formatNMS("net.minecraft.server.NMS.MojangsonParser"));
private Class<?> classItemStack = Class.forName(formatNMS("net.minecraft.server.NMS.ItemStack"));
private Class<?> classCraftItemStack = Class.forName(formatNMS("org.bukkit.craftbukkit.NMS.inventory.CraftItemStack"));
private Class<?> classNBTTagCompound = Class.forName(formatNMS("net.minecraft.server.NMS.NBTTagCompound"));
private Class<?> classBukkitItemStack = Class.forName("org.bukkit.inventory.ItemStack");
// reflected methods
private Method methodParseString;
private Method methodToItemStack;
private Method methodTobItemStack;
private Method methodTocItemStack;
private Method methodSaveTagToStack;
private Method methodToString;
/**
* Initializes all reflection methods
*
* @throws NoSuchMethodException
* @throws SecurityException
* @throws ClassNotFoundException
*/
public ItemSerializer() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
methodParseString = classMojangsonParser.getMethod("parse", String.class);
methodToItemStack = classItemStack.getMethod("a", classNBTTagCompound);
methodTobItemStack = classCraftItemStack.getMethod("asBukkitCopy", classItemStack);
methodTocItemStack = classCraftItemStack.getDeclaredMethod("asNMSCopy", classBukkitItemStack);
methodSaveTagToStack = classItemStack.getMethod("save", classNBTTagCompound);
methodToString = classNBTTagCompound.getMethod("toString");
}
/**
* Inserts the version declaration for any string containing NMS
*
* @param s the string to format, must contain NMS.
* @return formatted string
*/
private String formatNMS(String s) {
String packageName = Bukkit.getServer().getClass().getPackage().getName();
String nmsVersion = packageName.substring(packageName.lastIndexOf('.') + 1);
return s.replace("NMS", nmsVersion);
}
/**
* Deserializes a JSON String
*
* @param jsonString the JSON String to parse
* @return the deserialized ItemStack
*/
public ItemStack deserializeItemStackFromJson(String jsonString) {
try {
Object nbtTagCompound = methodParseString.invoke(null, jsonString);
Object citemStack = methodToItemStack.invoke(null, nbtTagCompound);
return (ItemStack) methodTobItemStack.invoke(null, citemStack);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* Serializes an item stack
*
* @param itemStack the ItemStack to parse
* @return condensed JSON String
*/
public String serializeItemStackToJson(ItemStack itemStack) {
try {
Object citemStack = methodTocItemStack.invoke(null, itemStack);
Object nbtTagCompoundObject = classNBTTagCompound.newInstance();
methodSaveTagToStack.invoke(citemStack, nbtTagCompoundObject);
return (String) methodToString.invoke(nbtTagCompoundObject);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Deserializes a string to an item stack, support both formats
*
* @param string the formatted string
* @return the deserialized ItemStack
*/
public ItemStack deserializeLegacyItemStack(String string) {
if(string.contains("{")) {
// string is json
return deserializeItemStackFromJson(string);
}
// old format
return deserializeItemStack(string);
}
/**
* This method is not able to handle skulls or in general nbt tags.
* Method is still existing for converting purposes.
*
* @deprecated use {@link #serializeItemStackToJson(ItemStack is)} instead.
*/
@Deprecated
public ItemStack deserializeItemStack(String string) {
string = string.replace("&", "§");
String[] splited = string.split("\\s+");
String[] val = splited[0].split(":");
ItemStack item = new ItemStack(Material.valueOf(val[0]));
if (item.getType() == Material.PLAYER_HEAD) {
item = new ItemStack(Material.PLAYER_HEAD, 1, (byte) 3);
}
ItemMeta meta = item.getItemMeta();
if (val.length == 2) {
item.setDurability(Short.parseShort(val[1]));
}
if (splited.length >= 2) {
if (Arconix.pl().getApi().doMath().isNumeric(splited[1])) {
item.setAmount(Integer.parseInt(splited[1]));
}
for (String st : splited) {
String str = unfixLine(st);
if (!str.contains(":")) continue;
String[] ops = str.split(":", 2);
String option = ops[0];
String value = ops[1];
if (Enchantment.getByName(option.replace(" ", "_").toUpperCase()) != null) {
Enchantment enchantment = Enchantment.getByName(option.replace(" ", "_").toUpperCase());
if (item.getType() != Material.ENCHANTED_BOOK) {
meta.addEnchant(enchantment, Integer.parseInt(value), true);
} else {
((EnchantmentStorageMeta) meta).addStoredEnchant(enchantment, Integer.parseInt(value), true);
}
}
String effect = "";
int duration = 0;
int hit = 0;
value = value.replace("_", " ");
switch (option) {
case "title":
if (item.getType() == Material.WRITTEN_BOOK) {
((BookMeta) meta).setTitle(value);
} else meta.setDisplayName(value);
break;
case "lore":
String[] parts = value.split("\\|");
ArrayList<String> lore = new ArrayList<>();
for (String line : parts)
lore.add(Arconix.pl().getApi().format().formatText(line));
meta.setLore(lore);
break;
case "player":
if (item.getType() == Material.PLAYER_HEAD) {
if (value.length() == 36)
((SkullMeta) meta).setOwningPlayer(Bukkit.getOfflinePlayer(UUID.fromString(value)));
else
((SkullMeta) meta).setOwner(value);
}
break;
case "author":
if (item.getType() == Material.WRITTEN_BOOK) {
((BookMeta) meta).setAuthor(value);
}
break;
case "effect":
case "duration":
hit++;
if (option.equalsIgnoreCase("effect")) {
effect = value;
} else {
duration = Integer.parseInt(value);
}
if (hit == 2) {
PotionEffect effect2 = PotionEffectType.getByName(effect).createEffect(duration, 0);
((PotionMeta) meta).addCustomEffect(effect2, false);
}
break;
case "id":
if (item.getType() == Material.WRITTEN_BOOK) {
if (!UltimateKits.getInstance().getDataFile().getConfig().contains("Books.pages." + value))
continue;
ConfigurationSection cs = UltimateKits.getInstance().getDataFile().getConfig().getConfigurationSection("Books.pages." + value);
for (String key : cs.getKeys(false)) {
((BookMeta) meta).addPage(UltimateKits.getInstance().getDataFile().getConfig().getString("Books.pages." + value + "." + key));
}
}
break;
case "color":
switch (item.getType()) {
case POTION:
//ToDO: this
break;
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
((LeatherArmorMeta) meta).setColor(Color.fromRGB(Integer.parseInt(value)));
break;
}
break;
}
}
}
item.setItemMeta(meta);
return item;
}
private String fixLine(String line) {
line = line.replace(" ", "_");
return line;
}
private String unfixLine(String line) {
line = line.replace("_", " ");
return line;
}
}

View File

@ -77,210 +77,6 @@ public class Methods {
return true;
}
/**
* Inserts the version declaration for any string containing NMS
*
* @param s the string to format, must contain NMS.
* @return formatted string
*/
public static String formatNMS(String s) {
String packageName = Bukkit.getServer().getClass().getPackage().getName();
String nmsVersion = packageName.substring(packageName.lastIndexOf('.') + 1);
return s.replace("NMS", nmsVersion);
}
/**
* Deserializes a JSON String
*
* @param jsonString the JSON String to parse
* @return the deserialized ItemStack
*/
public static ItemStack deserializeItemStackFromJson(String jsonString) {
try {
Method parseString = Class.forName(formatNMS("net.minecraft.server.NMS.MojangsonParser")).getMethod("parse", String.class);
Object nbtTagCompound = parseString.invoke(null, jsonString);
Method toItemStack = Class.forName(formatNMS("net.minecraft.server.NMS.ItemStack")).getMethod("a", nbtTagCompound.getClass());
Object citemStack = toItemStack.invoke(null, nbtTagCompound);
Method tobItemStack = Class.forName(formatNMS("org.bukkit.craftbukkit.NMS.inventory.CraftItemStack")).getMethod("asBukkitCopy", citemStack.getClass());
return (ItemStack) tobItemStack.invoke(null, citemStack);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* Serializes an item stack
*
* @param itemStack the ItemStack to parse
* @return condensed JSON String
*/
public static String serializeItemStackToJson(ItemStack itemStack) {
try {
Method tocItemStack = Class.forName(formatNMS("org.bukkit.craftbukkit.NMS.inventory.CraftItemStack")).getDeclaredMethod("asNMSCopy", Class.forName("org.bukkit.inventory.ItemStack"));
Object citemStack = tocItemStack.invoke(null, itemStack);
Object nbtTagCompoundObject = Class.forName(formatNMS("net.minecraft.server.NMS.NBTTagCompound")).newInstance();
Method saveTagToStack = citemStack.getClass().getMethod("save", nbtTagCompoundObject.getClass());
saveTagToStack.invoke(citemStack, nbtTagCompoundObject);
return (String) nbtTagCompoundObject.getClass().getMethod("toString").invoke(nbtTagCompoundObject);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Deserializes a string to an item stack, support both formats
*
* @param string the formatted string
* @return the deserialized ItemStack
*/
public static ItemStack deserializeLegacyItemStack(String string) {
if(string.contains("{")) {
// string is json
return deserializeItemStackFromJson(string);
}
// old format
return deserializeItemStack(string);
}
/**
* This method is not able to handle skulls or in general nbt tags.
* Method is still existing for converting purposes.
*
* @deprecated use {@link #serializeItemStackToJson(ItemStack is)} instead.
*/
@Deprecated
public static ItemStack deserializeItemStack(String string) {
string = string.replace("&", "§");
String[] splited = string.split("\\s+");
String[] val = splited[0].split(":");
ItemStack item = new ItemStack(Material.valueOf(val[0]));
if (item.getType() == Material.PLAYER_HEAD) {
item = new ItemStack(Material.PLAYER_HEAD, 1, (byte) 3);
}
ItemMeta meta = item.getItemMeta();
if (val.length == 2) {
item.setDurability(Short.parseShort(val[1]));
}
if (splited.length >= 2) {
if (Arconix.pl().getApi().doMath().isNumeric(splited[1])) {
item.setAmount(Integer.parseInt(splited[1]));
}
for (String st : splited) {
String str = unfixLine(st);
if (!str.contains(":")) continue;
String[] ops = str.split(":", 2);
String option = ops[0];
String value = ops[1];
if (Enchantment.getByName(option.replace(" ", "_").toUpperCase()) != null) {
Enchantment enchantment = Enchantment.getByName(option.replace(" ", "_").toUpperCase());
if (item.getType() != Material.ENCHANTED_BOOK) {
meta.addEnchant(enchantment, Integer.parseInt(value), true);
} else {
((EnchantmentStorageMeta) meta).addStoredEnchant(enchantment, Integer.parseInt(value), true);
}
}
String effect = "";
int duration = 0;
int hit = 0;
value = value.replace("_", " ");
switch (option) {
case "title":
if (item.getType() == Material.WRITTEN_BOOK) {
((BookMeta) meta).setTitle(value);
} else meta.setDisplayName(value);
break;
case "lore":
String[] parts = value.split("\\|");
ArrayList<String> lore = new ArrayList<>();
for (String line : parts)
lore.add(Arconix.pl().getApi().format().formatText(line));
meta.setLore(lore);
break;
case "player":
if (item.getType() == Material.PLAYER_HEAD) {
if (value.length() == 36)
((SkullMeta) meta).setOwningPlayer(Bukkit.getOfflinePlayer(UUID.fromString(value)));
else
((SkullMeta) meta).setOwner(value);
}
break;
case "author":
if (item.getType() == Material.WRITTEN_BOOK) {
((BookMeta) meta).setAuthor(value);
}
break;
case "effect":
case "duration":
hit++;
if (option.equalsIgnoreCase("effect")) {
effect = value;
} else {
duration = Integer.parseInt(value);
}
if (hit == 2) {
PotionEffect effect2 = PotionEffectType.getByName(effect).createEffect(duration, 0);
((PotionMeta) meta).addCustomEffect(effect2, false);
}
break;
case "id":
if (item.getType() == Material.WRITTEN_BOOK) {
if (!UltimateKits.getInstance().getDataFile().getConfig().contains("Books.pages." + value))
continue;
ConfigurationSection cs = UltimateKits.getInstance().getDataFile().getConfig().getConfigurationSection("Books.pages." + value);
for (String key : cs.getKeys(false)) {
((BookMeta) meta).addPage(UltimateKits.getInstance().getDataFile().getConfig().getString("Books.pages." + value + "." + key));
}
}
break;
case "color":
switch (item.getType()) {
case POTION:
//ToDO: this
break;
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
((LeatherArmorMeta) meta).setColor(Color.fromRGB(Integer.parseInt(value)));
break;
}
break;
}
}
}
item.setItemMeta(meta);
return item;
}
public static String fixLine(String line) {
line = line.replace(" ", "_");
return line;
}
public static String unfixLine(String line) {
line = line.replace("_", " ");
return line;
}
public static String getKitFromLocation(Location location) {
return UltimateKits.getInstance().getConfig().getString("data.block." + Arconix.pl().getApi().serialize().serializeLocation(location));