Beta version of better ItemStack serialization using a NBT <--> Gson converter.
This commit is contained in:
parent
34a7323f4a
commit
b4497f9b26
@ -3,6 +3,10 @@ package com.massivecraft.mcore4.adapter;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.server.NBTBase;
|
||||
import net.minecraft.server.NBTTagCompound;
|
||||
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@ -24,6 +28,7 @@ public class ItemStackAdapter implements JsonDeserializer<ItemStack>, JsonSerial
|
||||
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
|
||||
@ -45,39 +50,71 @@ public class ItemStackAdapter implements JsonDeserializer<ItemStack>, JsonSerial
|
||||
// JSON
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static JsonObject toJson(ItemStack itemStack)
|
||||
public static JsonObject toJson(ItemStack stack)
|
||||
{
|
||||
if (itemStack == null || itemStack.getTypeId() == 0 || itemStack.getAmount() == 0)
|
||||
// Check for "nothing"
|
||||
if (stack == null || stack.getTypeId() == 0 || stack.getAmount() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonObject jsonItemStack = new JsonObject();
|
||||
|
||||
jsonItemStack.addProperty(ItemStackAdapter.TYPE, itemStack.getTypeId());
|
||||
// Add type id
|
||||
jsonItemStack.addProperty(TYPE, stack.getTypeId());
|
||||
|
||||
if (itemStack.getAmount() != 1)
|
||||
// Add amount
|
||||
if (stack.getAmount() != 1)
|
||||
{
|
||||
jsonItemStack.addProperty(ItemStackAdapter.AMOUNT, itemStack.getAmount());
|
||||
jsonItemStack.addProperty(AMOUNT, stack.getAmount());
|
||||
}
|
||||
if (itemStack.getDurability() != 0) // Durability is a weird name since it is the amount of damage.
|
||||
|
||||
// Add damage
|
||||
if (stack.getDurability() != 0) // Durability is a weird name since it is the amount of damage.
|
||||
{
|
||||
jsonItemStack.addProperty(ItemStackAdapter.DAMAGE, itemStack.getDurability());
|
||||
jsonItemStack.addProperty(DAMAGE, stack.getDurability());
|
||||
}
|
||||
if (itemStack.getEnchantments().size() > 0)
|
||||
|
||||
// Add enchantments
|
||||
if (stack.getEnchantments().size() > 0)
|
||||
{
|
||||
JsonObject jsonEnchantments = new JsonObject();
|
||||
for (Entry<Enchantment, Integer> entry : itemStack.getEnchantments().entrySet())
|
||||
for (Entry<Enchantment, Integer> 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;
|
||||
}
|
||||
|
||||
// Used by method toJson
|
||||
public static JsonObject getEnchFreeGsonTagFromItemStack(ItemStack stack)
|
||||
{
|
||||
if (!(stack instanceof CraftItemStack)) return null;
|
||||
CraftItemStack craftItemStack = (CraftItemStack)stack;
|
||||
|
||||
NBTTagCompound nbt = craftItemStack.getHandle().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();
|
||||
@ -87,28 +124,37 @@ public class ItemStackAdapter implements JsonDeserializer<ItemStack>, JsonSerial
|
||||
int amount = 1;
|
||||
short damage = 0;
|
||||
|
||||
if (jsonItemStack.has(ItemStackAdapter.TYPE))
|
||||
if (jsonItemStack.has(TYPE))
|
||||
{
|
||||
type = jsonItemStack.get(ItemStackAdapter.TYPE).getAsInt();
|
||||
type = jsonItemStack.get(TYPE).getAsInt();
|
||||
}
|
||||
|
||||
if (jsonItemStack.has(ItemStackAdapter.AMOUNT))
|
||||
if (jsonItemStack.has(AMOUNT))
|
||||
{
|
||||
amount = jsonItemStack.get(ItemStackAdapter.AMOUNT).getAsInt();
|
||||
amount = jsonItemStack.get(AMOUNT).getAsInt();
|
||||
}
|
||||
|
||||
if (jsonItemStack.has(ItemStackAdapter.DAMAGE))
|
||||
if (jsonItemStack.has(DAMAGE))
|
||||
{
|
||||
damage = jsonItemStack.get(ItemStackAdapter.DAMAGE).getAsShort();
|
||||
damage = jsonItemStack.get(DAMAGE).getAsShort();
|
||||
}
|
||||
|
||||
// Create Non enchanted stack
|
||||
ItemStack stack = new ItemStack(type, amount, damage);
|
||||
CraftItemStack stack = new CraftItemStack(type, amount, damage);
|
||||
|
||||
// Add enchantments if there are any
|
||||
if (jsonItemStack.has(ItemStackAdapter.ENCHANTMENTS))
|
||||
// Add tag
|
||||
if (jsonItemStack.has(TAG))
|
||||
{
|
||||
JsonObject jsonEnchantments = jsonItemStack.get(ItemStackAdapter.ENCHANTMENTS).getAsJsonObject();
|
||||
JsonObject jsonbt = jsonItemStack.get(TAG).getAsJsonObject();
|
||||
CraftItemStack craftItemStack = stack;
|
||||
NBTBase nbt = NbtGsonConverter.gsonValToNbt(jsonbt, null, NBType.COMPOUND, NBType.UNKNOWN);
|
||||
craftItemStack.getHandle().tag = (NBTTagCompound) nbt;
|
||||
}
|
||||
|
||||
// Add enchantments if there are any
|
||||
if (jsonItemStack.has(ENCHANTMENTS))
|
||||
{
|
||||
JsonObject jsonEnchantments = jsonItemStack.get(ENCHANTMENTS).getAsJsonObject();
|
||||
for (Entry<String, JsonElement> enchantmentEntry: jsonEnchantments.entrySet())
|
||||
{
|
||||
int enchantmentId = Integer.valueOf(enchantmentEntry.getKey());
|
||||
|
93
src/com/massivecraft/mcore4/adapter/NBType.java
Normal file
93
src/com/massivecraft/mcore4/adapter/NBType.java
Normal file
@ -0,0 +1,93 @@
|
||||
package com.massivecraft.mcore4.adapter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.server.NBTBase;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public enum NBType
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// VALUES
|
||||
// -------------------------------------------- //
|
||||
|
||||
END(0, "end"),
|
||||
BYTE(1, "byte"),
|
||||
SHORT(2, "short"),
|
||||
INT(3, "int"),
|
||||
LONG(4, "long"),
|
||||
FLOAT(5, "float"),
|
||||
DOUBLE(6, "double"),
|
||||
BYTEARRAY(7, "bytearray"),
|
||||
STRING(8, "string"),
|
||||
LIST(9, "list"),
|
||||
COMPOUND(10, "compound"),
|
||||
INTARRAY(11, "intarray"),
|
||||
UNKNOWN(-1, "unknown"),
|
||||
;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FIELDS
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Getter final byte id;
|
||||
@Getter final String name;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
private NBType(int id, String name)
|
||||
{
|
||||
this.id = (byte)id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STATIC UTILS
|
||||
// -------------------------------------------- //
|
||||
|
||||
protected final static transient Map<String, NBType> tagnameToEnum = new HashMap<String, NBType>();
|
||||
protected final static transient Map<Byte, NBType> byteToEnum = new HashMap<Byte, NBType>();
|
||||
|
||||
static
|
||||
{
|
||||
for (NBType value : values())
|
||||
{
|
||||
tagnameToEnum.put(value.getName(), value);
|
||||
byteToEnum.put(value.getId(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public static NBType getByName(String name)
|
||||
{
|
||||
NBType ret = tagnameToEnum.get(name);
|
||||
if (ret == null)
|
||||
{
|
||||
ret = UNKNOWN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static NBType getById(byte id)
|
||||
{
|
||||
NBType ret = byteToEnum.get(id);
|
||||
if (ret == null)
|
||||
{
|
||||
ret = UNKNOWN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static NBType getByTag(NBTBase tag)
|
||||
{
|
||||
NBType ret = byteToEnum.get(tag.getTypeId());
|
||||
if (ret == null)
|
||||
{
|
||||
ret = UNKNOWN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
328
src/com/massivecraft/mcore4/adapter/NbtGsonConverter.java
Normal file
328
src/com/massivecraft/mcore4/adapter/NbtGsonConverter.java
Normal file
@ -0,0 +1,328 @@
|
||||
package com.massivecraft.mcore4.adapter;
|
||||
|
||||
import net.minecraft.server.NBTBase;
|
||||
import net.minecraft.server.NBTTagByte;
|
||||
import net.minecraft.server.NBTTagByteArray;
|
||||
import net.minecraft.server.NBTTagCompound;
|
||||
import net.minecraft.server.NBTTagDouble;
|
||||
import net.minecraft.server.NBTTagEnd;
|
||||
import net.minecraft.server.NBTTagFloat;
|
||||
import net.minecraft.server.NBTTagInt;
|
||||
import net.minecraft.server.NBTTagIntArray;
|
||||
import net.minecraft.server.NBTTagList;
|
||||
import net.minecraft.server.NBTTagLong;
|
||||
import net.minecraft.server.NBTTagShort;
|
||||
import net.minecraft.server.NBTTagString;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.massivecraft.mcore4.xlib.gson.JsonArray;
|
||||
import com.massivecraft.mcore4.xlib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.xlib.gson.JsonObject;
|
||||
import com.massivecraft.mcore4.xlib.gson.JsonPrimitive;
|
||||
|
||||
public class NbtGsonConverter
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// CONSTANTS
|
||||
// -------------------------------------------- //
|
||||
|
||||
public final static String TYPE = "type";
|
||||
public final static String ELEMTYPE = "elemtype";
|
||||
public final static String VAL = "val";
|
||||
public final static String NAME = "name";
|
||||
|
||||
// -------------------------------------------- //
|
||||
// GSON 2 NBT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static NBTBase gsonToNbt(JsonElement jsonElement)
|
||||
{
|
||||
return gsonToNbt(jsonElement, null);
|
||||
}
|
||||
|
||||
public static NBTBase gsonToNbt(JsonElement jsonElement, String name)
|
||||
{
|
||||
// Verify and cast the jsonElement into a jsonObject.
|
||||
// We could have used jsonObject as parameter type but this method signature is more flexible.
|
||||
if (!jsonElement.isJsonObject())
|
||||
{
|
||||
// must be a json object
|
||||
return null;
|
||||
}
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
|
||||
// Use the internal name if there is one
|
||||
JsonElement nameElement = jsonObject.get(NAME);
|
||||
if (nameElement != null)
|
||||
{
|
||||
name = nameElement.getAsString();
|
||||
}
|
||||
|
||||
// Fetch the type-info
|
||||
JsonElement typeElement = jsonObject.get(TYPE);
|
||||
if (typeElement == null)
|
||||
{
|
||||
// must have a type
|
||||
return null;
|
||||
}
|
||||
NBType type = NBType.getByName(typeElement.getAsString());
|
||||
|
||||
// Fetch the elemtype-info (used by NBTTagList only)
|
||||
NBType elemtype = NBType.UNKNOWN;
|
||||
if (type == NBType.LIST)
|
||||
{
|
||||
JsonElement elemtypeElement = jsonObject.get(ELEMTYPE);
|
||||
if (elemtypeElement == null)
|
||||
{
|
||||
// must have an elemtype
|
||||
return null;
|
||||
}
|
||||
elemtype = NBType.getByName(elemtypeElement.getAsString());
|
||||
}
|
||||
|
||||
// Fetch the value field
|
||||
JsonElement val = jsonObject.get(VAL);
|
||||
|
||||
// Convert the value based on the info we gathered
|
||||
return gsonValToNbt(val, name, type, elemtype);
|
||||
}
|
||||
|
||||
public static NBTBase gsonValToNbt(JsonElement val, String name, NBType type, NBType elemtype)
|
||||
{
|
||||
NBTBase ret = null;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case END:
|
||||
ret = new NBTTagEnd();
|
||||
break;
|
||||
|
||||
case BYTE:
|
||||
ret = new NBTTagByte(name, val.getAsByte());
|
||||
break;
|
||||
|
||||
case SHORT:
|
||||
ret = new NBTTagShort(name, val.getAsShort());
|
||||
break;
|
||||
|
||||
case INT:
|
||||
ret = new NBTTagInt(name, val.getAsInt());
|
||||
break;
|
||||
|
||||
case LONG:
|
||||
ret = new NBTTagLong(name, val.getAsLong());
|
||||
break;
|
||||
|
||||
case FLOAT:
|
||||
ret = new NBTTagFloat(name, val.getAsFloat());
|
||||
break;
|
||||
|
||||
case DOUBLE:
|
||||
ret = new NBTTagDouble(name, val.getAsDouble());
|
||||
break;
|
||||
|
||||
case BYTEARRAY:
|
||||
JsonArray jsonBytes = val.getAsJsonArray();
|
||||
int jsonBytesSize = jsonBytes.size();
|
||||
byte[] byteArray = new byte[jsonBytesSize];
|
||||
for (int index = 0 ; index < jsonBytesSize ; index++)
|
||||
{
|
||||
byte b = jsonBytes.get(index).getAsByte();
|
||||
byteArray[index] = b;
|
||||
}
|
||||
ret = new NBTTagByteArray(name, byteArray);
|
||||
break;
|
||||
|
||||
case INTARRAY:
|
||||
JsonArray jsonInts = val.getAsJsonArray();
|
||||
int jsonIntsSize = jsonInts.size();
|
||||
int[] intArray = new int[jsonIntsSize];
|
||||
for (int index = 0 ; index < jsonIntsSize ; index++)
|
||||
{
|
||||
int i = jsonInts.get(index).getAsInt();
|
||||
intArray[index] = i;
|
||||
}
|
||||
ret = new NBTTagIntArray(name, intArray);
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
ret = new NBTTagString(name, val.getAsString());
|
||||
break;
|
||||
|
||||
case LIST:
|
||||
NBTTagList nbtlist = new NBTTagList(name);
|
||||
|
||||
if (!val.isJsonArray())
|
||||
{
|
||||
// must be an array
|
||||
return null;
|
||||
}
|
||||
|
||||
Iterator<JsonElement> iter = val.getAsJsonArray().iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
nbtlist.add(gsonValToNbt(iter.next(), null, elemtype, NBType.UNKNOWN));
|
||||
}
|
||||
ret = nbtlist;
|
||||
break;
|
||||
|
||||
case COMPOUND:
|
||||
NBTTagCompound compound = new NBTTagCompound(name);
|
||||
|
||||
if (!val.isJsonObject())
|
||||
{
|
||||
// must be an object
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonObject jsonCompound = val.getAsJsonObject();
|
||||
|
||||
for(Entry<String, JsonElement> entry : jsonCompound.entrySet())
|
||||
{
|
||||
String childName = entry.getKey();
|
||||
JsonElement childJson = entry.getValue();
|
||||
NBTBase child = gsonToNbt(childJson, childName);
|
||||
if (child == null) continue;
|
||||
compound.set(childName, child);
|
||||
}
|
||||
|
||||
ret = compound;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// NBT TO GSON
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static JsonObject nbtToGson(NBTBase nbt, boolean includeName)
|
||||
{
|
||||
JsonObject ret = new JsonObject();
|
||||
|
||||
String name = nbt.getName();
|
||||
if (includeName && name != null)
|
||||
{
|
||||
ret.addProperty(NAME, name);
|
||||
}
|
||||
|
||||
NBType type = NBType.getById(nbt.getTypeId());
|
||||
ret.addProperty(TYPE, type.getName());
|
||||
|
||||
if (type == NBType.LIST)
|
||||
{
|
||||
ret.addProperty(ELEMTYPE, NBType.getByTag(((NBTTagList)nbt).get(0)).getName());
|
||||
}
|
||||
|
||||
JsonElement val = nbtToGsonVal(nbt);
|
||||
if (val == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ret.add(VAL, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static JsonElement nbtToGsonVal(NBTBase nbt)
|
||||
{
|
||||
JsonElement val = null;
|
||||
|
||||
NBType type = NBType.getByTag(nbt);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case END:
|
||||
// this should never happen
|
||||
break;
|
||||
|
||||
case BYTE:
|
||||
val = new JsonPrimitive(((NBTTagByte) nbt).data);
|
||||
break;
|
||||
|
||||
case SHORT:
|
||||
val = new JsonPrimitive(((NBTTagShort) nbt).data);
|
||||
break;
|
||||
|
||||
case INT:
|
||||
val = new JsonPrimitive(((NBTTagInt) nbt).data);
|
||||
break;
|
||||
|
||||
case LONG:
|
||||
val = new JsonPrimitive(((NBTTagLong) nbt).data);
|
||||
break;
|
||||
|
||||
case FLOAT:
|
||||
val = new JsonPrimitive(((NBTTagFloat) nbt).data);
|
||||
break;
|
||||
|
||||
case DOUBLE:
|
||||
val = new JsonPrimitive(((NBTTagDouble) nbt).data);
|
||||
break;
|
||||
|
||||
case BYTEARRAY:
|
||||
JsonArray jsonBytes = new JsonArray();
|
||||
for (byte elem : ((NBTTagByteArray) nbt).data)
|
||||
{
|
||||
jsonBytes.add(new JsonPrimitive(elem));
|
||||
}
|
||||
val = jsonBytes;
|
||||
break;
|
||||
|
||||
case INTARRAY:
|
||||
JsonArray jsonInts = new JsonArray();
|
||||
for (int elem : ((NBTTagIntArray) nbt).data)
|
||||
{
|
||||
jsonInts.add(new JsonPrimitive(elem));
|
||||
}
|
||||
val = jsonInts;
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
val = new JsonPrimitive(((NBTTagString) nbt).data);
|
||||
break;
|
||||
|
||||
case LIST:
|
||||
NBTTagList nbtlist = (NBTTagList)nbt;
|
||||
int size = nbtlist.size();
|
||||
if (size <= 0)
|
||||
{
|
||||
// NBTTagList may not be empty
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonArray jsonElems = new JsonArray();
|
||||
for (int i = 0 ; i < size ; i++)
|
||||
{
|
||||
jsonElems.add(nbtToGsonVal(nbtlist.get(i)));
|
||||
}
|
||||
val = jsonElems;
|
||||
break;
|
||||
|
||||
case COMPOUND:
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
for (NBTBase child : getCompoundChildren((NBTTagCompound)nbt))
|
||||
{
|
||||
jsonObject.add(child.getName(), nbtToGson(child, false));
|
||||
}
|
||||
val = jsonObject;
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// UTILS
|
||||
// -------------------------------------------- //
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Collection<NBTBase> getCompoundChildren(NBTTagCompound compound)
|
||||
{
|
||||
return (Collection<NBTBase>)compound.c();
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
@ -149,6 +150,22 @@ public class MUtil
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static <K, V> Map<V, K> flippedMap(Map<K, V> map)
|
||||
{
|
||||
Map<V, K> ret = new LinkedHashMap<V, K>();
|
||||
|
||||
for(Entry<K, V> entry : map.entrySet())
|
||||
{
|
||||
V value = entry.getValue();
|
||||
K key = entry.getKey();
|
||||
|
||||
if (value == null) continue;
|
||||
ret.put(value, key);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// LE NICE RANDOM
|
||||
// -------------------------------------------- //
|
||||
|
Loading…
Reference in New Issue
Block a user