diff --git a/itemstackformat.txt b/itemstackformat.txt new file mode 100644 index 00000000..e871c42d --- /dev/null +++ b/itemstackformat.txt @@ -0,0 +1,123 @@ +# ============================================= +# Vanilla NBT prented as pseudo-json +# ============================================= + +{ + id: short + Count: byte + Damage: short + tag: + { + display: + { + Name: str + Lore: [str] + color: int + } + ench: + [ + { + id: int + lvl: int + } + { + id: int + lvl: int + } + ... + ] + title: str + author: str + pages: [str] + map_is_scaling: byte + SkullOwner: str + CustomPotionEffects: + [ + { + ID: byte + Amplifier: byte + Duration: int + Amplifier: bool + } + ... + ] + } +} + +# ============================================= +# Bukkit YAML prented as pseudo-json +# ============================================= + +{ + type: str + damage: short + amount: int + meta: + { + meta-type: BOOK, SKULL, LEATHER_ARMOR, MAP, POTION or UNSPECIFIC + display-name: str + lore: [str] + enchants: + { + id: lvl + ... + } + repair-cost: int + title: str + author: str + pages: [str] + color: + { + RED: int + BLUE: int + GREEN: int + } + scaling: byte + skull-owner: str + custom-effects: + [ + { + effect: int + duration: int + amplifier: int + ambient: bool + } + ... + ] + } +} + +# ============================================= +# MassiveCraft Json prented as pseudo-json +# ============================================= + +{ + id: int + count: int + damage: short + name: str + lore: [str] + enchants: + { + id: lvl + id: lvl + ... + } + repaircost: int + title: str + author: str + pages: [str] + color: int + scaling: bool + skull: str + effects: + [ + { + id: int + duration: int + amplifier: int + ambient: bool + } + ... + ] +} \ No newline at end of file diff --git a/src/com/massivecraft/mcore5/MCore.java b/src/com/massivecraft/mcore5/MCore.java index cbcf8d4f..b133de09 100644 --- a/src/com/massivecraft/mcore5/MCore.java +++ b/src/com/massivecraft/mcore5/MCore.java @@ -45,8 +45,8 @@ public class MCore extends MPlugin .disableHtmlEscaping() .excludeFieldsWithModifiers(Modifier.TRANSIENT) .registerTypeAdapter(MongoURI.class, MongoURIAdapter.get()) - .registerTypeAdapter(ItemStack.class, new ItemStackAdapter()) - .registerTypeAdapter(Inventory.class, new InventoryAdapter()) + .registerTypeAdapter(ItemStack.class, ItemStackAdapter.get()) + .registerTypeAdapter(Inventory.class, InventoryAdapter.get()) .registerTypeAdapter(PS.class, new PSAdapter()); } diff --git a/src/com/massivecraft/mcore5/adapter/InventoryAdapter.java b/src/com/massivecraft/mcore5/adapter/InventoryAdapter.java index 463e78fd..cf336f6e 100644 --- a/src/com/massivecraft/mcore5/adapter/InventoryAdapter.java +++ b/src/com/massivecraft/mcore5/adapter/InventoryAdapter.java @@ -6,6 +6,7 @@ import org.bukkit.craftbukkit.v1_4_5.inventory.CraftInventoryCustom; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import com.massivecraft.mcore5.MCore; import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext; import com.massivecraft.mcore5.xlib.gson.JsonDeserializer; import com.massivecraft.mcore5.xlib.gson.JsonElement; @@ -52,7 +53,7 @@ public class InventoryAdapter implements JsonDeserializer, JsonSerial for (int i = 0; i < itemStacks.length; i++) { ItemStack itemStack = itemStacks[i]; - JsonObject jsonItemStack = ItemStackAdapter.toJson(itemStack); + JsonElement jsonItemStack = MCore.gson.toJsonTree(itemStack, ItemStack.class); if (jsonItemStack == null) continue; jsonInventory.add(String.valueOf(i), jsonItemStack); } @@ -75,7 +76,7 @@ public class InventoryAdapter implements JsonDeserializer, JsonSerial // Fetch the jsonItemStack or mark it as empty and continue String stackIdx = String.valueOf(i); JsonElement jsonItemStack = jsonInventory.get(stackIdx); - ItemStack itemStack = ItemStackAdapter.fromJson(jsonItemStack); + ItemStack itemStack = MCore.gson.fromJson(jsonItemStack, ItemStack.class); itemStacks[i] = itemStack; } @@ -101,4 +102,12 @@ public class InventoryAdapter implements JsonDeserializer, JsonSerial } return true; } + + // -------------------------------------------- // + // INSTANCE + // -------------------------------------------- // + + public static InventoryAdapter i = new InventoryAdapter(); + public static InventoryAdapter get() { return i; } + } \ No newline at end of file diff --git a/src/com/massivecraft/mcore5/adapter/ItemStackAdapter.java b/src/com/massivecraft/mcore5/adapter/ItemStackAdapter.java index fc0cd77f..01acf424 100644 --- a/src/com/massivecraft/mcore5/adapter/ItemStackAdapter.java +++ b/src/com/massivecraft/mcore5/adapter/ItemStackAdapter.java @@ -1,14 +1,6 @@ package com.massivecraft.mcore5.adapter; -import java.lang.reflect.Field; import java.lang.reflect.Type; -import java.util.Map.Entry; - -import net.minecraft.server.v1_4_5.NBTBase; -import net.minecraft.server.v1_4_5.NBTTagCompound; - -import org.bukkit.craftbukkit.v1_4_5.inventory.CraftItemStack; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext; @@ -21,16 +13,6 @@ import com.massivecraft.mcore5.xlib.gson.JsonSerializer; public class ItemStackAdapter implements JsonDeserializer, JsonSerializer { - // -------------------------------------------- // - // FIELD NAME CONSTANTS - // -------------------------------------------- // - - public static final String TYPE = "type"; - public static final String AMOUNT = "amount"; - public static final String DAMAGE = "damage"; - public static final String ENCHANTMENTS = "enchantments"; - public static final String TAG = "tag"; - // -------------------------------------------- // // IMPLEMENTATION // -------------------------------------------- // @@ -38,168 +20,47 @@ public class ItemStackAdapter implements JsonDeserializer, JsonSerial @Override public JsonElement serialize(ItemStack itemStack, Type typeOfSrc, JsonSerializationContext context) { - return toJson(itemStack); + // We always use the latest version when we serialize. + return ItemStackAdapterV2.erialize(itemStack); } @Override public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - return fromJson(json); + // We need to decide what version to use when we deserialize. + JsonDeserializer deserializer = pickItemStackDeserializer(json); + return deserializer.deserialize(json, typeOfT, context); } // -------------------------------------------- // - // JSON + // PICK ITEM STACK ADAPTER // -------------------------------------------- // - public static JsonObject toJson(ItemStack stack) + protected static JsonDeserializer pickItemStackDeserializer(JsonElement jsonElement) { + JsonDeserializer ret = ItemStackAdapterV2.get(); + // Check for "nothing" - if (stack == null || stack.getTypeId() == 0 || stack.getAmount() == 0) + if (jsonElement == null) return ret; + + // Must be a JsonObject + if (jsonElement.isJsonObject() == false) return ret; + JsonObject json = jsonElement.getAsJsonObject(); + + // Is it V1? + if (json.has(ItemStackAdapterV1.TYPE)) { - return null; + ret = ItemStackAdapterV1.get(); } - JsonObject jsonItemStack = new JsonObject(); - - // Add type id - jsonItemStack.addProperty(TYPE, stack.getTypeId()); - - // Add amount - if (stack.getAmount() != 1) - { - jsonItemStack.addProperty(AMOUNT, stack.getAmount()); - } - - // Add damage - if (stack.getDurability() != 0) // Durability is a weird name since it is the amount of damage. - { - jsonItemStack.addProperty(DAMAGE, stack.getDurability()); - } - - // Add enchantments - if (stack.getEnchantments().size() > 0) - { - JsonObject jsonEnchantments = new JsonObject(); - for (Entry entry : stack.getEnchantments().entrySet()) - { - jsonEnchantments.addProperty(String.valueOf(entry.getKey().getId()), entry.getValue()); - } - jsonItemStack.add(ItemStackAdapter.ENCHANTMENTS, jsonEnchantments); - } - - // Add the tag if there is one - JsonObject tag = getEnchFreeGsonTagFromItemStack(stack); - if (tag != null) - { - jsonItemStack.add(TAG, tag); - } - - return jsonItemStack; + return ret; } - - // Used by method toJson - public static JsonObject getEnchFreeGsonTagFromItemStack(ItemStack stack) - { - if (!(stack instanceof CraftItemStack)) return null; - CraftItemStack craftItemStack = (CraftItemStack)stack; - - NBTTagCompound nbt = getHandle(craftItemStack).tag; - if (nbt == null) return null; - - JsonObject gsonbt = (JsonObject) NbtGsonConverter.nbtToGsonVal(nbt); - gsonbt.remove("ench"); - if (gsonbt.entrySet().size() == 0) return null; - - return gsonbt; - } - - public static ItemStack fromJson(JsonElement json) - { - // Check for "nothing" - if (json == null || ! json.isJsonObject()) return null; - - JsonObject jsonItemStack = json.getAsJsonObject(); - - // Populate values - int type = 0; - int amount = 1; - short damage = 0; - - if (jsonItemStack.has(TYPE)) - { - type = jsonItemStack.get(TYPE).getAsInt(); - } - - if (jsonItemStack.has(AMOUNT)) - { - amount = jsonItemStack.get(AMOUNT).getAsInt(); - } - - if (jsonItemStack.has(DAMAGE)) - { - damage = jsonItemStack.get(DAMAGE).getAsShort(); - } - - // Create Non enchanted stack - ItemStack stack = new ItemStack(type, amount, damage); - - // Add tag - if (jsonItemStack.has(TAG)) - { - JsonObject jsonbt = jsonItemStack.get(TAG).getAsJsonObject(); - - CraftItemStack craftItemStack = CraftItemStack.asCraftCopy(stack); - stack = craftItemStack; - - NBTBase nbt = NbtGsonConverter.gsonValToNbt(jsonbt, null, NBType.COMPOUND, NBType.UNKNOWN); - - getHandle(craftItemStack).tag = (NBTTagCompound) nbt; - } - - // Add enchantments if there are any - if (jsonItemStack.has(ENCHANTMENTS)) - { - JsonObject jsonEnchantments = jsonItemStack.get(ENCHANTMENTS).getAsJsonObject(); - for (Entry enchantmentEntry: jsonEnchantments.entrySet()) - { - int enchantmentId = Integer.valueOf(enchantmentEntry.getKey()); - Integer enchantmentLevel = Integer.valueOf(enchantmentEntry.getValue().getAsString()); - stack.addUnsafeEnchantment(Enchantment.getById(enchantmentId), enchantmentLevel); - } - } - - return stack; - } - + // -------------------------------------------- // - // GET HANDLE + // INSTANCE // -------------------------------------------- // - public static Field fieldCraftItemStackDotHandle = null; + public static ItemStackAdapter i = new ItemStackAdapter(); + public static ItemStackAdapter get() { return i; } - static - { - try - { - fieldCraftItemStackDotHandle = CraftItemStack.class.getDeclaredField("handle"); - fieldCraftItemStackDotHandle.setAccessible(true); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - public static net.minecraft.server.v1_4_5.ItemStack getHandle(CraftItemStack craftItemStack) - { - try - { - return (net.minecraft.server.v1_4_5.ItemStack) fieldCraftItemStackDotHandle.get(craftItemStack); - } - catch (Exception e) - { - e.printStackTrace(); - return null; - } - } } diff --git a/src/com/massivecraft/mcore5/adapter/ItemStackAdapterV1.java b/src/com/massivecraft/mcore5/adapter/ItemStackAdapterV1.java new file mode 100644 index 00000000..045d8ec9 --- /dev/null +++ b/src/com/massivecraft/mcore5/adapter/ItemStackAdapterV1.java @@ -0,0 +1,214 @@ +package com.massivecraft.mcore5.adapter; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.Map.Entry; + +import net.minecraft.server.v1_4_5.NBTBase; +import net.minecraft.server.v1_4_5.NBTTagCompound; + +import org.bukkit.craftbukkit.v1_4_5.inventory.CraftItemStack; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + +import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext; +import com.massivecraft.mcore5.xlib.gson.JsonDeserializer; +import com.massivecraft.mcore5.xlib.gson.JsonElement; +import com.massivecraft.mcore5.xlib.gson.JsonObject; +import com.massivecraft.mcore5.xlib.gson.JsonParseException; +import com.massivecraft.mcore5.xlib.gson.JsonSerializationContext; +import com.massivecraft.mcore5.xlib.gson.JsonSerializer; + +// TODO: This adapter is deprecated as of 2012-12-20. It should be removed in some time. +public class ItemStackAdapterV1 implements JsonDeserializer, JsonSerializer +{ + // -------------------------------------------- // + // FIELD NAME CONSTANTS + // -------------------------------------------- // + + public static final String TYPE = "type"; + public static final String AMOUNT = "amount"; + public static final String DAMAGE = "damage"; + public static final String ENCHANTMENTS = "enchantments"; + public static final String TAG = "tag"; + + // -------------------------------------------- // + // IMPLEMENTATION + // -------------------------------------------- // + + @Override + public JsonElement serialize(ItemStack itemStack, Type typeOfSrc, JsonSerializationContext context) + { + return toJson(itemStack); + } + + @Override + public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException + { + return fromJson(json); + } + + // -------------------------------------------- // + // JSON + // -------------------------------------------- // + + public static JsonObject toJson(ItemStack stack) + { + // Check for "nothing" + if (stack == null || stack.getTypeId() == 0 || stack.getAmount() == 0) + { + return null; + } + + JsonObject jsonItemStack = new JsonObject(); + + // Add type id + jsonItemStack.addProperty(TYPE, stack.getTypeId()); + + // Add amount + if (stack.getAmount() != 1) + { + jsonItemStack.addProperty(AMOUNT, stack.getAmount()); + } + + // Add damage + if (stack.getDurability() != 0) // Durability is a weird name since it is the amount of damage. + { + jsonItemStack.addProperty(DAMAGE, stack.getDurability()); + } + + // Add enchantments + if (stack.getEnchantments().size() > 0) + { + JsonObject jsonEnchantments = new JsonObject(); + for (Entry entry : stack.getEnchantments().entrySet()) + { + jsonEnchantments.addProperty(String.valueOf(entry.getKey().getId()), entry.getValue()); + } + jsonItemStack.add(ItemStackAdapterV1.ENCHANTMENTS, jsonEnchantments); + } + + // Add the tag if there is one + JsonObject tag = getEnchFreeGsonTagFromItemStack(stack); + if (tag != null) + { + jsonItemStack.add(TAG, tag); + } + + return jsonItemStack; + } + + // Used by method toJson + public static JsonObject getEnchFreeGsonTagFromItemStack(ItemStack stack) + { + if (!(stack instanceof CraftItemStack)) return null; + CraftItemStack craftItemStack = (CraftItemStack)stack; + + NBTTagCompound nbt = getHandle(craftItemStack).tag; + if (nbt == null) return null; + + JsonObject gsonbt = (JsonObject) NbtGsonConverter.nbtToGsonVal(nbt); + gsonbt.remove("ench"); + if (gsonbt.entrySet().size() == 0) return null; + + return gsonbt; + } + + public static ItemStack fromJson(JsonElement json) + { + // Check for "nothing" + if (json == null || ! json.isJsonObject()) return null; + + JsonObject jsonItemStack = json.getAsJsonObject(); + + // Populate values + int type = 0; + int amount = 1; + short damage = 0; + + if (jsonItemStack.has(TYPE)) + { + type = jsonItemStack.get(TYPE).getAsInt(); + } + + if (jsonItemStack.has(AMOUNT)) + { + amount = jsonItemStack.get(AMOUNT).getAsInt(); + } + + if (jsonItemStack.has(DAMAGE)) + { + damage = jsonItemStack.get(DAMAGE).getAsShort(); + } + + // Create Non enchanted stack + ItemStack stack = new ItemStack(type, amount, damage); + + // Add tag + if (jsonItemStack.has(TAG)) + { + JsonObject jsonbt = jsonItemStack.get(TAG).getAsJsonObject(); + + CraftItemStack craftItemStack = CraftItemStack.asCraftCopy(stack); + stack = craftItemStack; + + NBTBase nbt = NbtGsonConverter.gsonValToNbt(jsonbt, null, NBType.COMPOUND, NBType.UNKNOWN); + + getHandle(craftItemStack).tag = (NBTTagCompound) nbt; + } + + // Add enchantments if there are any + if (jsonItemStack.has(ENCHANTMENTS)) + { + JsonObject jsonEnchantments = jsonItemStack.get(ENCHANTMENTS).getAsJsonObject(); + for (Entry enchantmentEntry: jsonEnchantments.entrySet()) + { + int enchantmentId = Integer.valueOf(enchantmentEntry.getKey()); + Integer enchantmentLevel = Integer.valueOf(enchantmentEntry.getValue().getAsString()); + stack.addUnsafeEnchantment(Enchantment.getById(enchantmentId), enchantmentLevel); + } + } + + return stack; + } + + // -------------------------------------------- // + // GET HANDLE + // -------------------------------------------- // + + public static Field fieldCraftItemStackDotHandle = null; + + static + { + try + { + fieldCraftItemStackDotHandle = CraftItemStack.class.getDeclaredField("handle"); + fieldCraftItemStackDotHandle.setAccessible(true); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public static net.minecraft.server.v1_4_5.ItemStack getHandle(CraftItemStack craftItemStack) + { + try + { + return (net.minecraft.server.v1_4_5.ItemStack) fieldCraftItemStackDotHandle.get(craftItemStack); + } + catch (Exception e) + { + e.printStackTrace(); + return null; + } + } + + // -------------------------------------------- // + // INSTANCE + // -------------------------------------------- // + + public static ItemStackAdapterV1 i = new ItemStackAdapterV1(); + public static ItemStackAdapterV1 get() { return i; } + +} diff --git a/src/com/massivecraft/mcore5/adapter/ItemStackAdapterV2.java b/src/com/massivecraft/mcore5/adapter/ItemStackAdapterV2.java new file mode 100644 index 00000000..9219465d --- /dev/null +++ b/src/com/massivecraft/mcore5/adapter/ItemStackAdapterV2.java @@ -0,0 +1,560 @@ +package com.massivecraft.mcore5.adapter; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import org.bukkit.Color; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.MapMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.Repairable; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.potion.PotionEffect; + +import com.massivecraft.mcore5.xlib.gson.JsonArray; +import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext; +import com.massivecraft.mcore5.xlib.gson.JsonDeserializer; +import com.massivecraft.mcore5.xlib.gson.JsonElement; +import com.massivecraft.mcore5.xlib.gson.JsonObject; +import com.massivecraft.mcore5.xlib.gson.JsonParseException; +import com.massivecraft.mcore5.xlib.gson.JsonPrimitive; +import com.massivecraft.mcore5.xlib.gson.JsonSerializationContext; +import com.massivecraft.mcore5.xlib.gson.JsonSerializer; + +/** + * This is a GSON serializer/deserializer for the Bukkit ItemStack. + * Why not use the built in Bukkit serializer/deserializer? I would have loved to do that :) + * but sadly that one is YAML centric and cannot be used with json in a good way. + * This serializer requires manual updating to work but produces clean json. + * See the file itemstackformat.txt for more info. + */ +public class ItemStackAdapterV2 implements JsonDeserializer, JsonSerializer +{ + // -------------------------------------------- // + // FIELD NAME CONSTANTS + // -------------------------------------------- // + + public static final String ID = "id"; + public static final String COUNT = "count"; + public static final String DAMAGE = "damage"; + + public static final String NAME = "name"; + public static final String LORE = "lore"; + + public static final String ENCHANTS = "enchants"; + + public static final String REPAIRCOST = "repaircost"; + + public static final String BOOK_TITLE = "title"; + public static final String BOOK_AUTHOR = "author"; + public static final String BOOK_PAGES = "pages"; + + public static final String LEATHER_ARMOR_COLOR = "color"; + + public static final String MAP_SCALING = "scaling"; + + public static final String SKULL_OWNER = "skull"; + + public static final String POTION_EFFECTS = "effects"; + + // -------------------------------------------- // + // OTHER CONSTANTS + // -------------------------------------------- // + + public static final int DEFAULT_ID; + public static final int DEFAULT_COUNT; + public static final int DEFAULT_DAMAGE; + + // TODO: Awaiting https://bukkit.atlassian.net/browse/BUKKIT-3203 + static final Color DEFAULT_LEATHER_COLOR = Color.fromRGB(0xA06540); + + static + { + ItemStack stack = createItemStack(); + DEFAULT_ID = stack.getTypeId(); + DEFAULT_COUNT = stack.getAmount(); + DEFAULT_DAMAGE = stack.getDurability(); + } + + // -------------------------------------------- // + // GSON INTERFACE IMPLEMENTATION + // -------------------------------------------- // + + @Override + public JsonElement serialize(ItemStack src, Type typeOfSrc, JsonSerializationContext context) + { + return erialize(src); + } + + @Override + public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException + { + return erialize(json); + } + + // -------------------------------------------- // + // WRITE + // -------------------------------------------- // + + public static JsonObject erialize(ItemStack stack) + { + // Check for "nothing" + if (stack == null) return null; + if (stack.getTypeId() == 0) return null; + if (stack.getAmount() == 0) return null; + + // Create a new JsonObject + JsonObject json = new JsonObject(); + + // Transfer data from stack to json + transferAll(stack, json, true); + + return json; + } + + public static ItemStack erialize(JsonElement jsonElement) + { + // Check for "nothing" + if (jsonElement == null) return null; + + // Must be a JsonObject + if (jsonElement.isJsonObject() == false) return null; + JsonObject json = jsonElement.getAsJsonObject(); + + // Create a new ItemStack + ItemStack stack = createItemStack(); + + // Transfer data from json to stack + transferAll(stack, json, false); + + return stack; + } + + // -------------------------------------------- // + // NOARG STACK CONSTRUCTOR + // -------------------------------------------- // + + public static ItemStack createItemStack() + { + return new ItemStack(0); + } + + // -------------------------------------------- // + // ALL + // -------------------------------------------- // + + public static void transferAll(ItemStack stack, JsonObject json, boolean stack2json) + { + transferBasic(stack, json, stack2json); + + ItemMeta meta = stack.getItemMeta(); + transferMeta(meta, json, stack2json); + + if (stack2json == false) + { + stack.setItemMeta(meta); + } + } + + // -------------------------------------------- // + // BASIC + // -------------------------------------------- // + + public static void transferBasic(ItemStack stack, JsonObject json, boolean stack2json) + { + transferId(stack, json, stack2json); + transferCount(stack, json, stack2json); + transferDamage(stack, json, stack2json); + } + + // -------------------------------------------- // + // BASIC: ID + // -------------------------------------------- // + + public static void transferId(ItemStack stack, JsonObject json, boolean stack2json) + { + if (stack2json) + { + int id = stack.getTypeId(); + if (id == DEFAULT_ID) return; + json.addProperty(ID, id); + } + else + { + JsonElement element = json.get(ID); + if (element == null) return; + stack.setTypeId(element.getAsInt()); + } + } + + // -------------------------------------------- // + // BASIC: COUNT + // -------------------------------------------- // + + public static void transferCount(ItemStack stack, JsonObject json, boolean stack2json) + { + if (stack2json) + { + int count = stack.getAmount(); + if (count == DEFAULT_COUNT) return; + json.addProperty(COUNT, count); + } + else + { + JsonElement element = json.get(COUNT); + if (element == null) return; + stack.setAmount(element.getAsInt()); + } + } + + // -------------------------------------------- // + // BASIC: DAMAGE + // -------------------------------------------- // + + public static void transferDamage(ItemStack stack, JsonObject json, boolean stack2json) + { + // Durability is a weird name since it is the amount of damage. + if (stack2json) + { + int damage = stack.getDurability(); + if (damage == DEFAULT_DAMAGE) return; + json.addProperty(DAMAGE, damage); + } + else + { + JsonElement element = json.get(DAMAGE); + if (element == null) return; + stack.setDurability(element.getAsShort()); + } + } + + // -------------------------------------------- // + // META + // -------------------------------------------- // + + public static void transferMeta(ItemMeta meta, JsonObject json, boolean meta2json) + { + transferUnspecificMeta(meta, json, meta2json); + transferSpecificMeta(meta, json, meta2json); + } + + // -------------------------------------------- // + // UNSPECIFIC META + // -------------------------------------------- // + + public static void transferUnspecificMeta(ItemMeta meta, JsonObject json, boolean meta2json) + { + transferName(meta, json, meta2json); + transferLore(meta, json, meta2json); + transferEnchants(meta, json, meta2json); + transferRepaircost(meta, json, meta2json); + } + + // -------------------------------------------- // + // UNSPECIFIC META: NAME + // -------------------------------------------- // + + public static void transferName(ItemMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasDisplayName()) return; + json.addProperty(NAME, meta.getDisplayName()); + } + else + { + JsonElement element = json.get(NAME); + if (element == null) return; + meta.setDisplayName(element.getAsString()); + } + } + + // -------------------------------------------- // + // UNSPECIFIC META: LORE + // -------------------------------------------- // + + public static void transferLore(ItemMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasLore()) return; + json.add(LORE, fromStringCollection(meta.getLore())); + } + else + { + JsonElement element = json.get(LORE); + if (element == null) return; + meta.setLore(toStringCollection(element)); + } + } + + // -------------------------------------------- // + // UNSPECIFIC META: ENCHANTS + // -------------------------------------------- // + + public static void transferEnchants(ItemMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasEnchants()) return; + + JsonObject enchants = new JsonObject(); + for (Entry entry : meta.getEnchants().entrySet()) + { + enchants.addProperty(String.valueOf(entry.getKey().getId()), entry.getValue()); + } + + json.add(ENCHANTS, enchants); + } + else + { + JsonElement element = json.get(ENCHANTS); + if (element == null) return; + + JsonObject jsonEnchantments = element.getAsJsonObject(); + for (Entry enchantmentEntry: jsonEnchantments.entrySet()) + { + int id = Integer.valueOf(enchantmentEntry.getKey()); + Enchantment ench = Enchantment.getById(id); + int lvl = enchantmentEntry.getValue().getAsInt(); + meta.addEnchant(ench, lvl, true); + } + } + } + + // -------------------------------------------- // + // UNSPECIFIC META: REPAIRCOST + // -------------------------------------------- // + + public static void transferRepaircost(ItemMeta meta, JsonObject json, boolean meta2json) + { + if ( ! (meta instanceof Repairable)) return; + Repairable repairable = (Repairable)meta; + + if (meta2json) + { + if ( ! repairable.hasRepairCost()) return; + json.addProperty(REPAIRCOST, repairable.getRepairCost()); + } + else + { + JsonElement element = json.get(REPAIRCOST); + if (element == null) return; + + repairable.setRepairCost(element.getAsInt()); + } + } + + // -------------------------------------------- // + // SPECIFIC META + // -------------------------------------------- // + + public static void transferSpecificMeta(ItemMeta meta, JsonObject json, boolean meta2json) + { + if (meta instanceof BookMeta) + { + transferBookMeta((BookMeta) meta, json, meta2json); + } + else if (meta instanceof LeatherArmorMeta) + { + transferLeatherArmorMeta((LeatherArmorMeta) meta, json, meta2json); + } + else if (meta instanceof MapMeta) + { + transferMapMeta((MapMeta) meta, json, meta2json); + } + else if (meta instanceof PotionMeta) + { + transferPotionMeta((PotionMeta) meta, json, meta2json); + } + else if (meta instanceof SkullMeta) + { + transferSkullMeta((SkullMeta) meta, json, meta2json); + } + } + + // -------------------------------------------- // + // SPECIFIC META: BOOK + // -------------------------------------------- // + + public static void transferBookMeta(BookMeta meta, JsonObject json, boolean meta2json) + { + transferTitle(meta, json, meta2json); + transferAuthor(meta, json, meta2json); + transferPages(meta, json, meta2json); + } + + public static void transferTitle(BookMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasTitle()) return; + json.addProperty(BOOK_TITLE, meta.getTitle()); + } + else + { + JsonElement element = json.get(BOOK_TITLE); + if (element == null) return; + meta.setTitle(element.getAsString()); + } + } + + public static void transferAuthor(BookMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasTitle()) return; + json.addProperty(BOOK_AUTHOR, meta.getAuthor()); + } + else + { + JsonElement element = json.get(BOOK_AUTHOR); + if (element == null) return; + meta.setAuthor(element.getAsString()); + } + } + + public static void transferPages(BookMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasTitle()) return; + json.add(BOOK_PAGES, fromStringCollection(meta.getPages())); + } + else + { + JsonElement element = json.get(BOOK_PAGES); + if (element == null) return; + meta.setPages(toStringCollection(element)); + } + } + + // -------------------------------------------- // + // SPECIFIC META: LEATHER ARMOR + // -------------------------------------------- // + + public static void transferLeatherArmorMeta(LeatherArmorMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + Color color = meta.getColor(); + if (DEFAULT_LEATHER_COLOR.equals(color)) return; + + json.addProperty(LEATHER_ARMOR_COLOR, color.asRGB()); + } + else + { + JsonElement element = json.get(LEATHER_ARMOR_COLOR); + if (element == null) return; + meta.setColor(Color.fromRGB(element.getAsInt())); + } + } + + // -------------------------------------------- // + // SPECIFIC META: MAP + // -------------------------------------------- // + + public static void transferMapMeta(MapMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.isScaling()) return; + json.addProperty(MAP_SCALING, true); + } + else + { + JsonElement element = json.get(MAP_SCALING); + if (element == null) return; + + meta.setScaling(element.getAsBoolean()); + } + } + + // -------------------------------------------- // + // SPECIFIC META: POTION + // -------------------------------------------- // + + public static void transferPotionMeta(PotionMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasCustomEffects()) return; + json.add(POTION_EFFECTS, PotionEffectsAdapter.toJson(meta.getCustomEffects())); + } + else + { + JsonElement element = json.get(POTION_EFFECTS); + if (element == null) return; + + meta.clearCustomEffects(); + for (PotionEffect pe : PotionEffectsAdapter.fromJson(element)) + { + meta.addCustomEffect(pe, false); + } + } + } + + // -------------------------------------------- // + // SPECIFIC META: SKULL + // -------------------------------------------- // + + public static void transferSkullMeta(SkullMeta meta, JsonObject json, boolean meta2json) + { + if (meta2json) + { + if ( ! meta.hasOwner()) return; + json.addProperty(SKULL_OWNER, meta.getOwner()); + } + else + { + JsonElement element = json.get(SKULL_OWNER); + if (element == null) return; + meta.setOwner(element.getAsString()); + } + } + + // -------------------------------------------- // + // MINI UTILS + // -------------------------------------------- // + + public static JsonArray fromStringCollection(Collection strings) + { + JsonArray ret = new JsonArray(); + for (String string : strings) + { + ret.add(new JsonPrimitive(string)); + } + return ret; + } + + public static List toStringCollection(JsonElement json) + { + JsonArray array = json.getAsJsonArray(); + List ret = new ArrayList(); + + Iterator iter = array.iterator(); + while (iter.hasNext()) + { + JsonElement element = iter.next(); + ret.add(element.getAsString()); + } + + return ret; + } + + // -------------------------------------------- // + // INSTANCE + // -------------------------------------------- // + + public static ItemStackAdapterV2 i = new ItemStackAdapterV2(); + public static ItemStackAdapterV2 get() { return i; } + +} diff --git a/src/com/massivecraft/mcore5/adapter/NbtGsonConverter.java b/src/com/massivecraft/mcore5/adapter/NbtGsonConverter.java index fbd44850..23c02bf8 100644 --- a/src/com/massivecraft/mcore5/adapter/NbtGsonConverter.java +++ b/src/com/massivecraft/mcore5/adapter/NbtGsonConverter.java @@ -23,6 +23,7 @@ import com.massivecraft.mcore5.xlib.gson.JsonElement; import com.massivecraft.mcore5.xlib.gson.JsonObject; import com.massivecraft.mcore5.xlib.gson.JsonPrimitive; +//TODO: This converter is deprecated as of 2012-12-20. It should be removed in some time. public class NbtGsonConverter { // -------------------------------------------- // diff --git a/src/com/massivecraft/mcore5/adapter/PSAdapter.java b/src/com/massivecraft/mcore5/adapter/PSAdapter.java index d58f8974..8f3334b3 100644 --- a/src/com/massivecraft/mcore5/adapter/PSAdapter.java +++ b/src/com/massivecraft/mcore5/adapter/PSAdapter.java @@ -45,9 +45,7 @@ public class PSAdapter implements JsonDeserializer // INSTANCE // -------------------------------------------- // - protected static PSAdapter instance = new PSAdapter(); - public static PSAdapter get() - { - return instance; - } + public static PSAdapter i = new PSAdapter(); + public static PSAdapter get() { return i; } + } diff --git a/src/com/massivecraft/mcore5/adapter/PotionEffectAdapter.java b/src/com/massivecraft/mcore5/adapter/PotionEffectAdapter.java new file mode 100644 index 00000000..15917e00 --- /dev/null +++ b/src/com/massivecraft/mcore5/adapter/PotionEffectAdapter.java @@ -0,0 +1,56 @@ +package com.massivecraft.mcore5.adapter; + +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import com.massivecraft.mcore5.xlib.gson.JsonElement; +import com.massivecraft.mcore5.xlib.gson.JsonObject; + +public class PotionEffectAdapter +{ + // -------------------------------------------- // + // FIELD CONSTANTS + // -------------------------------------------- // + + public static final String POTION_EFFECT_ID = "id"; + public static final String POTION_DURATION = "duration"; + public static final String POTION_AMPLIFIER = "amplifier"; + public static final String POTION_AMBIENT = "ambient"; + + // -------------------------------------------- // + // TO JSON + // -------------------------------------------- // + + public static JsonObject toJson(PotionEffect potionEffect) + { + if (potionEffect == null) return null; + + JsonObject ret = new JsonObject(); + + ret.addProperty(POTION_EFFECT_ID, potionEffect.getType().getId()); + ret.addProperty(POTION_DURATION, potionEffect.getDuration()); + ret.addProperty(POTION_AMPLIFIER, potionEffect.getAmplifier()); + ret.addProperty(POTION_AMBIENT, potionEffect.isAmbient()); + + return ret; + } + + // -------------------------------------------- // + // FROM JSON + // -------------------------------------------- // + + public static PotionEffect fromJson(JsonElement jsonElement) + { + if (jsonElement == null) return null; + if ( ! jsonElement.isJsonObject()) return null; + + JsonObject json = jsonElement.getAsJsonObject(); + + PotionEffectType pet = PotionEffectType.getById(json.get(POTION_EFFECT_ID).getAsInt()); + int duration = json.get(POTION_DURATION).getAsInt(); + int amplifier = json.get(POTION_AMPLIFIER).getAsInt(); + boolean ambient = json.get(POTION_AMBIENT).getAsBoolean(); + + return new PotionEffect(pet, duration, amplifier, ambient); + } +} diff --git a/src/com/massivecraft/mcore5/adapter/PotionEffectsAdapter.java b/src/com/massivecraft/mcore5/adapter/PotionEffectsAdapter.java new file mode 100644 index 00000000..68f512f0 --- /dev/null +++ b/src/com/massivecraft/mcore5/adapter/PotionEffectsAdapter.java @@ -0,0 +1,52 @@ +package com.massivecraft.mcore5.adapter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.bukkit.potion.PotionEffect; + +import com.massivecraft.mcore5.xlib.gson.JsonArray; +import com.massivecraft.mcore5.xlib.gson.JsonElement; + +public class PotionEffectsAdapter +{ + // -------------------------------------------- // + // TO JSON + // -------------------------------------------- // + + public static JsonArray toJson(Collection potionEffects) + { + JsonArray ret = new JsonArray(); + for (PotionEffect pe : potionEffects) + { + ret.add(PotionEffectAdapter.toJson(pe)); + } + return ret; + } + + // -------------------------------------------- // + // FROM JSON + // -------------------------------------------- // + + public static List fromJson(JsonElement jsonElement) + { + if (jsonElement == null) return null; + if ( ! jsonElement.isJsonArray()) return null; + JsonArray array = jsonElement.getAsJsonArray(); + + List ret = new ArrayList(); + + Iterator iter = array.iterator(); + while(iter.hasNext()) + { + PotionEffect pe = PotionEffectAdapter.fromJson(iter.next()); + if (pe == null) continue; + ret.add(pe); + } + + return ret; + } + +} diff --git a/src/com/massivecraft/mcore5/store/Coll.java b/src/com/massivecraft/mcore5/store/Coll.java index 3a40541f..9586a186 100644 --- a/src/com/massivecraft/mcore5/store/Coll.java +++ b/src/com/massivecraft/mcore5/store/Coll.java @@ -385,8 +385,12 @@ public class Coll implements CollInterface this.getStoreAdapter().write(this, raw, entity); + // this.lastRaw.put(id, this.getStoreAdapter().read(this, entity)); // Store adapter again since result of a database read may be "different" from entity read. - this.lastRaw.put(id, this.getStoreAdapter().read(this, entity)); + // WARN: This was causing many issues with config files not updating etc. + // The approach below may not work with MongoDB at all since that is not tested. + this.lastRaw.put(id, raw); + this.lastMtime.put(id, mtime); this.lastDefault.remove(id); } @@ -452,7 +456,7 @@ public class Coll implements CollInterface { Object lastRaw = this.lastRaw.get(id); Object currentRaw = this.storeAdapter.read(this, entity); - return (currentRaw.equals(lastRaw) == false); + return (this.getDriver().equal(currentRaw, lastRaw) == false); } @Override diff --git a/src/com/massivecraft/mcore5/store/Driver.java b/src/com/massivecraft/mcore5/store/Driver.java index 711876b8..df73debd 100644 --- a/src/com/massivecraft/mcore5/store/Driver.java +++ b/src/com/massivecraft/mcore5/store/Driver.java @@ -17,6 +17,9 @@ public interface Driver // Could for example be JsonElement or DBObject public Class getRawdataClass(); + // Comparison of raw data should be done through this method + public boolean equal(Object rawOne, Object rawTwo); + // This is some sort of database specific id strategy with built in adapter public boolean registerIdStrategy(IdStrategy idStrategy); public IdStrategy getIdStrategy(String idStrategyName); diff --git a/src/com/massivecraft/mcore5/store/DriverGson.java b/src/com/massivecraft/mcore5/store/DriverGson.java index e388a1fd..75aa7d4c 100644 --- a/src/com/massivecraft/mcore5/store/DriverGson.java +++ b/src/com/massivecraft/mcore5/store/DriverGson.java @@ -30,6 +30,18 @@ public class DriverGson extends DriverAbstract @Override public Class getRawdataClass() { return JsonElement.class; } + @Override + public boolean equal(Object rawOne, Object rawTwo) + { + JsonElement one = (JsonElement)rawOne; + JsonElement two = (JsonElement)rawTwo; + + if (one == null && two == null) return true; + if (one == null || two == null) return false; + + return one.toString().equals(two.toString()); + } + @Override public StoreAdapter getStoreAdapter() { diff --git a/src/com/massivecraft/mcore5/store/DriverMongo.java b/src/com/massivecraft/mcore5/store/DriverMongo.java index 93b4db9c..0320f6e6 100644 --- a/src/com/massivecraft/mcore5/store/DriverMongo.java +++ b/src/com/massivecraft/mcore5/store/DriverMongo.java @@ -40,6 +40,18 @@ public class DriverMongo extends DriverAbstract @Override public Class getRawdataClass() { return BasicDBObject.class; } + @Override + public boolean equal(Object rawOne, Object rawTwo) + { + BasicDBObject one = (BasicDBObject)rawOne; + BasicDBObject two = (BasicDBObject)rawTwo; + + if (one == null && two == null) return true; + if (one == null || two == null) return false; + + return one.equals(two); + } + @Override public StoreAdapter getStoreAdapter() {