fix saving of custom items

This commit is contained in:
Aurora 2020-08-07 15:27:53 +02:00
parent fe43bc35b5
commit 1621536206
9 changed files with 355 additions and 208 deletions

View File

@ -22,8 +22,8 @@ import com.songoda.epicbosses.utils.IReloadable;
import com.songoda.epicbosses.utils.Message;
import com.songoda.epicbosses.utils.ServerUtils;
import com.songoda.epicbosses.utils.file.YmlFileHandler;
import com.songoda.epicbosses.utils.itemstack.ItemSerializer;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.ArrayList;
@ -70,6 +70,7 @@ public class EpicBosses extends SongodaPlugin implements IReloadable {
private YmlFileHandler langFileHandler, editorFileHandler, displayFileHandler;
private FileConfiguration lang, editor, display;
private ItemSerializer itemSerializer;
private boolean debug = true;
@ -133,6 +134,11 @@ public class EpicBosses extends SongodaPlugin implements IReloadable {
this.bossEntityManager = new BossEntityManager(this);
this.autoSpawnManager = new AutoSpawnManager(this);
try {
this.itemSerializer = new ItemSerializer();
} catch (Throwable t) {
t.printStackTrace();
}
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"))
new PlaceholderManager(this).register();
@ -391,6 +397,10 @@ public class EpicBosses extends SongodaPlugin implements IReloadable {
return this.display;
}
public ItemSerializer getItemSerializer() {
return itemSerializer;
}
public boolean isDebug() {
return this.debug;
}

View File

@ -6,6 +6,8 @@ import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.songoda.epicbosses.utils.file.FileHandler;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolder;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderJson;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderLegacy;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
@ -47,7 +49,9 @@ public class ItemStackFileHandler extends FileHandler<Map<String, ItemStackHolde
if (jsonObject != null) {
jsonObject.entrySet().forEach(entry -> {
String id = entry.getKey();
ItemStackHolder itemStackHolder = GSON.fromJson(entry.getValue(), ItemStackHolder.class);
ItemStackHolder itemStackHolder = entry.getValue().getAsJsonObject().has("json")
? GSON.fromJson(entry.getValue(), ItemStackHolderJson.class)
: GSON.fromJson(entry.getValue(), ItemStackHolderLegacy.class);
itemStackHolderMap.put(id, itemStackHolder);
});

View File

@ -0,0 +1,110 @@
package com.songoda.epicbosses.utils.itemstack;
import com.songoda.core.compatibility.ServerVersion;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
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");
private Constructor<?> constructorItemStack;
// reflected methods
private Method methodParseString;
private Method methodCreateStack;
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);
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13))
methodToItemStack = classItemStack.getMethod("a", classNBTTagCompound);
else if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11))
constructorItemStack = classItemStack.getConstructor(classNBTTagCompound);
else
methodCreateStack = classItemStack.getMethod("createStack", 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;
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13))
citemStack = methodToItemStack.invoke(null, nbtTagCompound);
else if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11))
citemStack = constructorItemStack.newInstance(nbtTagCompound);
else
citemStack = methodCreateStack.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;
}
}
}

View File

@ -1,23 +1,15 @@
package com.songoda.epicbosses.utils.itemstack;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.epicbosses.utils.IReplaceableConverter;
import com.songoda.epicbosses.utils.StringUtils;
import com.songoda.epicbosses.utils.itemstack.converters.EnchantConverter;
import com.songoda.epicbosses.utils.itemstack.converters.MaterialConverter;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolder;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderJson;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.bukkit.inventory.meta.ItemMeta;
/**
* @author Charles Cullen
@ -26,68 +18,13 @@ import java.util.Map;
*/
public class ItemStackConverter implements IReplaceableConverter<ItemStackHolder, ItemStack> {
private MaterialConverter materialConverter;
private EnchantConverter enchantConverter;
public ItemStackConverter() {
this.materialConverter = new MaterialConverter();
this.enchantConverter = new EnchantConverter();
}
@Override
public ItemStackHolder to(ItemStack itemStack) {
Material material = itemStack.getType();
int amount = itemStack.getAmount();
Short durability = itemStack.getDurability(), spawnerId = null;
String type, name = null, skullOwner = null;
List<String> lore = null, enchants = null;
if (durability == 0) {
durability = null;
try {
return new ItemStackHolderJson(new ItemSerializer().serializeItemStackToJson(itemStack));
} catch (Throwable t) {
return null;
}
type = this.materialConverter.to(material);
if (itemStack.hasItemMeta()) {
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta.hasDisplayName()) {
name = itemMeta.getDisplayName().replace('§', '&');
}
if (itemMeta.hasLore()) {
lore = new ArrayList<>();
for (String string : itemMeta.getLore()) {
lore.add(string.replace('§', '&'));
}
}
if (itemMeta.hasEnchants()) {
enchants = this.enchantConverter.to(itemMeta.getEnchants());
}
if (itemMeta instanceof SkullMeta) {
SkullMeta skullMeta = (SkullMeta) itemMeta;
if (skullMeta.hasOwner()) {
skullOwner = skullMeta.getOwner();
}
}
if (itemMeta instanceof BlockStateMeta) {
BlockStateMeta blockStateMeta = (BlockStateMeta) itemMeta;
BlockState blockState = blockStateMeta.getBlockState();
if (blockState instanceof CreatureSpawner) {
CreatureSpawner creatureSpawner = (CreatureSpawner) blockState;
spawnerId = creatureSpawner.getSpawnedType().getTypeId();
}
}
}
return new ItemStackHolder(amount, type, durability, name, lore, enchants, skullOwner, spawnerId);
}
@Override
@ -100,32 +37,19 @@ public class ItemStackConverter implements IReplaceableConverter<ItemStackHolder
ItemStack itemStack = new ItemStack(Material.AIR);
if (itemStackHolder == null) return itemStack;
if (itemStackHolder.getType() == null) return itemStack;
CompatibleMaterial cMaterial = CompatibleMaterial.getMaterial(itemStackHolder.getType());
Material material = cMaterial.getMaterial();
if (material == null) return itemStack;
itemStack.setType(material);
Integer amount = itemStackHolder.getAmount();
Short durability = (short) cMaterial.getData(), spawnerId = itemStackHolder.getSpawnerId();
String name = itemStackHolder.getName(), skullOwner = itemStackHolder.getSkullOwner();
List<String> lore = itemStackHolder.getLore(), enchants = itemStackHolder.getEnchants();
if (durability != -1) itemStack.setDurability(durability);
if (enchants != null) itemStack.addUnsafeEnchantments(this.enchantConverter.from(enchants));
if (name != null || skullOwner != null || lore != null || spawnerId != null) {
ItemStack loaded = itemStackHolder.getItemStack();
if (loaded == null) return itemStack;
itemStack = loaded;
if(itemStack.hasItemMeta()) {
ItemMeta itemMeta = itemStack.getItemMeta();
//-----------
// SET NAME
//-----------
if (name != null) {
name = StringUtils.get().translateColor(name);
if (itemMeta.hasDisplayName()) {
String name = StringUtils.get().translateColor(itemMeta.getDisplayName());
itemMeta.setDisplayName(replaceString(name, replaceMap));
}
@ -133,40 +57,15 @@ public class ItemStackConverter implements IReplaceableConverter<ItemStackHolder
//-----------
// SET LORE
//-----------
if (lore != null) {
List<String> replacedLore = new ArrayList<>(lore);
if (itemMeta.hasLore()) {
List<String> replacedLore = new ArrayList<>(itemMeta.getLore());
replacedLore.replaceAll(s -> s.replace('&', '§'));
replacedLore.replaceAll(s -> replaceString(s, replaceMap));
itemMeta.setLore(replacedLore);
}
//----------------------------------------------
// SET OWNER, SPAWNER ID, OR UPDATE ITEM META
//----------------------------------------------
if (skullOwner != null) {
SkullMeta skullMeta = (SkullMeta) itemMeta;
skullMeta.setOwner(skullOwner);
itemStack.setItemMeta(skullMeta);
} else if (spawnerId != null) {
BlockStateMeta blockStateMeta = (BlockStateMeta) itemMeta;
BlockState blockState = blockStateMeta.getBlockState();
CreatureSpawner creatureSpawner = (CreatureSpawner) blockState;
creatureSpawner.setSpawnedType(EntityType.fromId(spawnerId));
blockStateMeta.setBlockState(blockState);
itemStack.setItemMeta(blockStateMeta);
} else {
itemStack.setItemMeta(itemMeta);
}
}
if (amount != null && amount > 1) {
itemStack.setAmount(amount);
}
return itemStack;
}

View File

@ -4,9 +4,13 @@ import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.epicbosses.utils.IConverter;
import com.songoda.epicbosses.utils.exceptions.NotImplementedException;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolder;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderJson;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderLegacy;
import java.util.Arrays;
import org.bukkit.configuration.ConfigurationSection;
import java.util.List;
import org.bukkit.entity.EntityType;
/**
* @author Charles Cullen
@ -18,28 +22,7 @@ public class ItemStackHolderConverter implements IConverter<ItemStackHolder, Con
@Override
public ItemStackHolder to(ConfigurationSection configurationSection) {
if (configurationSection == null) return null;
Integer amount = (Integer) configurationSection.get("amount", null);
CompatibleMaterial material = CompatibleMaterial.getMaterial(configurationSection.getString("type", null));
String type;
if (material == null)
type = "STONE";
else
type = material.getMaterial() == null ? "STONE" : material.getMaterial().name();
Short durability = (Short) configurationSection.get("durability", null);
if (material.getData() != -1) durability = (short) material.getData();
String name = configurationSection.getString("name", null);
List<String> lore = (List<String>) configurationSection.getList("lore", null);
List<String> enchants = (List<String>) configurationSection.getList("enchants", null);
String skullOwner = configurationSection.getString("skullOwner", null);
Short spawnerId = (Short) configurationSection.get("spawnerId", null);
//Boolean isGlowing = (Boolean) configurationSection.get("isGlowing", null);
return new ItemStackHolder(amount, type, durability, name, lore, enchants, skullOwner, spawnerId);
return ItemStackUtils.getItemStackHolder(configurationSection);
}
@Override

View File

@ -7,6 +7,8 @@ import com.songoda.epicbosses.utils.ServerUtils;
import com.songoda.epicbosses.utils.StringUtils;
import com.songoda.epicbosses.utils.itemstack.enchants.GlowEnchant;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolder;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderJson;
import com.songoda.epicbosses.utils.itemstack.holder.ItemStackHolderLegacy;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
@ -383,6 +385,10 @@ public class ItemStackUtils {
@SuppressWarnings("unchecked")
public static ItemStackHolder getItemStackHolder(ConfigurationSection configurationSection) {
if (configurationSection == null) return null;
if (configurationSection.getKeys(false).contains("json"))
return new ItemStackHolderJson(configurationSection.getString("json", null));
Integer amount = (Integer) configurationSection.get("amount", null);
CompatibleMaterial material = CompatibleMaterial.getMaterial(configurationSection.getString("type", null));
@ -394,10 +400,10 @@ public class ItemStackUtils {
List<String> lore = (List<String>) configurationSection.getList("lore", null);
List<String> enchants = (List<String>) configurationSection.getList("enchants", null);
String skullOwner = configurationSection.getString("skullOwner", null);
Short spawnerId = (Short) configurationSection.get("spawnerId", null);
EntityType spawnerId = Arrays.stream(EntityType.values()).filter(e -> e.name().equalsIgnoreCase(configurationSection.getString("spawnerId", null))).findFirst().orElse(null);
//Boolean isGlowing = (Boolean) configurationSection.get("isGlowing", null);
return new ItemStackHolder(amount, type, durability, name, lore, enchants, skullOwner, spawnerId);
return new ItemStackHolderLegacy(amount, type, durability, name, lore, enchants, skullOwner, spawnerId);
}
public static boolean isItemStackSame(ItemStack itemStack1, ItemStack itemStack2) {
@ -427,4 +433,4 @@ public class ItemStackUtils {
return true;
}
}
}

View File

@ -1,73 +1,12 @@
package com.songoda.epicbosses.utils.itemstack.holder;
import com.google.gson.annotations.Expose;
import java.util.List;
import org.bukkit.inventory.ItemStack;
/**
* @author Charles Cullen
* @version 1.0.0
* @since 03-Jun-18
*/
public class ItemStackHolder {
@Expose
private Integer amount;
@Expose
private String type;
@Expose
private Short durability;
@Expose
private String name;
@Expose
private List<String> lore;
@Expose
private List<String> enchants;
@Expose
private String skullOwner;
@Expose
private Short spawnerId;
public ItemStackHolder(Integer amount, String type, Short durability, String name, List<String> lore, List<String> enchants, String skullOwner, Short spawnerId) {
this.amount = amount;
this.type = type;
this.durability = durability;
this.name = name;
this.lore = lore;
this.enchants = enchants;
this.skullOwner = skullOwner;
this.spawnerId = spawnerId;
}
public Integer getAmount() {
return this.amount;
}
public String getType() {
return this.type;
}
public Short getDurability() {
return this.durability;
}
public String getName() {
return this.name;
}
public List<String> getLore() {
return this.lore;
}
public List<String> getEnchants() {
return this.enchants;
}
public String getSkullOwner() {
return this.skullOwner;
}
public Short getSpawnerId() {
return this.spawnerId;
}
public interface ItemStackHolder {
public ItemStack getItemStack();
}

View File

@ -0,0 +1,47 @@
package com.songoda.epicbosses.utils.itemstack.holder;
import com.google.gson.annotations.Expose;
import com.songoda.epicbosses.utils.itemstack.ItemSerializer;
import java.util.List;
import org.bukkit.inventory.ItemStack;
/**
* @author Charles Cullen
* @version 1.0.0
* @since 03-Jun-18
*/
public class ItemStackHolderJson implements ItemStackHolder {
private static final ItemSerializer serializer;
static {
ItemSerializer is;
try {
is = new ItemSerializer();
} catch (Exception e) {
is = null;
e.printStackTrace();
}
serializer = is;
}
@Expose
private final String json;
public ItemStackHolderJson(String json) {
this.json = json;
}
public String getJson() {
return this.json;
}
public ItemStack getItemStack() {
try {
return serializer.deserializeItemStackFromJson(json);
} catch (Exception e) {
return null;
}
}
}

View File

@ -0,0 +1,149 @@
package com.songoda.epicbosses.utils.itemstack.holder;
import com.google.gson.annotations.Expose;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.epicbosses.utils.StringUtils;
import com.songoda.epicbosses.utils.itemstack.converters.EnchantConverter;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
/**
* @author Charles Cullen
* @version 1.0.0
* @since 03-Jun-18
*/
public class ItemStackHolderLegacy implements ItemStackHolder {
public static final EnchantConverter enchantConverter = new EnchantConverter();
@Expose
private Integer amount;
@Expose
private String type;
@Expose
private Short durability;
@Expose
private String name;
@Expose
private List<String> lore;
@Expose
private List<String> enchants;
@Expose
private String skullOwner;
@Expose
private EntityType spawnerId;
public ItemStackHolderLegacy(Integer amount, String type, Short durability, String name, List<String> lore, List<String> enchants, String skullOwner, EntityType spawnerId) {
this.amount = amount;
this.type = type;
this.durability = durability;
this.name = name;
this.lore = lore;
this.enchants = enchants;
this.skullOwner = skullOwner;
this.spawnerId = spawnerId;
}
public Integer getAmount() {
return this.amount;
}
public String getType() {
return this.type;
}
public Short getDurability() {
return this.durability;
}
public String getName() {
return this.name;
}
public List<String> getLore() {
return this.lore;
}
public List<String> getEnchants() {
return this.enchants;
}
public String getSkullOwner() {
return this.skullOwner;
}
public EntityType getSpawnerId() {
return this.spawnerId;
}
@Override
public ItemStack getItemStack() {
ItemStack itemStack = new ItemStack(Material.AIR);
if (this.type == null) return itemStack;
CompatibleMaterial cMaterial = CompatibleMaterial.getMaterial(this.type);
Material material = cMaterial.getMaterial();
if (material == null) return itemStack;
itemStack.setType(material);
if (this.durability != null && this.durability != -1) itemStack.setDurability(this.durability);
if (this.enchants != null) itemStack.addUnsafeEnchantments(ItemStackHolderLegacy.enchantConverter.from(this.enchants));
if (this.name != null || this.skullOwner != null || this.lore != null || this.spawnerId != null) {
ItemMeta itemMeta = itemStack.getItemMeta();
//-----------
// SET NAME
//-----------
if (this.name != null) {
String name = StringUtils.get().translateColor(this.name);
itemMeta.setDisplayName(name);
}
//-----------
// SET LORE
//-----------
if (this.lore != null) {
List<String> replacedLore = new ArrayList<>(this.lore);
replacedLore.replaceAll(s -> s.replace('&', '§'));
itemMeta.setLore(replacedLore);
}
//----------------------------------------------
// SET OWNER, SPAWNER ID, OR UPDATE ITEM META
//----------------------------------------------
if (this.skullOwner != null) {
SkullMeta skullMeta = (SkullMeta) itemMeta;
skullMeta.setOwner(this.skullOwner);
itemStack.setItemMeta(skullMeta);
} else if (this.spawnerId != null) {
BlockStateMeta blockStateMeta = (BlockStateMeta) itemMeta;
BlockState blockState = blockStateMeta.getBlockState();
CreatureSpawner creatureSpawner = (CreatureSpawner) blockState;
creatureSpawner.setSpawnedType(this.spawnerId);
blockStateMeta.setBlockState(blockState);
itemStack.setItemMeta(blockStateMeta);
} else {
itemStack.setItemMeta(itemMeta);
}
}
if (amount != null && amount > 1) {
itemStack.setAmount(amount);
}
return itemStack;
}
}