org.arkhamnetwork.playersync.utils.SerializationUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.arkhamnetwork.playersync.utils.SerializationUtils.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.arkhamnetwork.playersync.utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.server.v1_7_R4.NBTBase;
import net.minecraft.server.v1_7_R4.NBTNumber;
import net.minecraft.server.v1_7_R4.NBTTagByteArray;
import net.minecraft.server.v1_7_R4.NBTTagCompound;
import net.minecraft.server.v1_7_R4.NBTTagDouble;
import net.minecraft.server.v1_7_R4.NBTTagInt;
import net.minecraft.server.v1_7_R4.NBTTagIntArray;
import net.minecraft.server.v1_7_R4.NBTTagList;
import net.minecraft.server.v1_7_R4.NBTTagLong;
import net.minecraft.server.v1_7_R4.NBTTagString;
import org.apache.commons.lang.SerializationException;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

/**
 *
 * @author devan_000
 */
public class SerializationUtils {

    private static final ItemStack AIR = new ItemStack(36, 0);

    public static byte[] serializeItemStacks(ItemStack[] inv) throws SerializationException, IOException {
        NBTTagCompound baseTag = new NBTTagCompound();
        NBTTagList inventoryTag = new NBTTagList();

        int current = 0;

        for (ItemStack stack : inv) {
            if (stack == null) {
                stack = new ItemStack(Material.AIR, 1);
            }
            if (stack.getType() != Material.AIR) {
                NBTTagCompound item = new NBTTagCompound();
                item.setByte("InvSize", (byte) inv.length);
                item.setByte("CurrentSlot", (byte) current);
                inventoryTag.add(CraftItemStack.asNMSCopy(stack).save(item));
            }
            current++;
        }

        baseTag.set("Inventory", inventoryTag);

        Map<String, Object> map = toMap(baseTag);
        return JSONObject.toJSONString(map).getBytes();
    }

    public static ItemStack[] deserializeItemStacks(byte[] b)
            throws SerializationException, ParseException, IOException, ClassNotFoundException {
        if (b == null) {
            return null;
        }
        NBTTagCompound baseTag = toTag(JSONValue.parseWithException(new String(b)).toString());
        NBTTagList inventoryTag = baseTag.getList("Inventory", 10);
        Map<Integer, ItemStack> itemMap = new ConcurrentHashMap<>();

        final int invSize = inventoryTag.get(0).getByte("InvSize");

        for (int i = 0; i < inventoryTag.size(); i++) {
            NBTTagCompound item = inventoryTag.get(i);

            int slot = item.getByte("CurrentSlot");
            if (!itemMap.containsKey(slot)) {
                itemMap.put(slot,
                        CraftItemStack.asCraftMirror(net.minecraft.server.v1_7_R4.ItemStack.createStack(item)));
            }
        }

        List<ItemStack> items = new ArrayList<>();
        for (int i = 0; i < invSize; i++) {
            if (i > invSize) {
                break;
            }

            if (itemMap.get(i) == null) {
                items.add(AIR.clone());
                continue;
            }

            items.add(itemMap.get(i));
            //IMPORTANT
            itemMap.remove(i);
        }

        return items.toArray(new ItemStack[items.size()]);
    }

    public static byte[] serializePotionEffects(PotionEffect[] ef) throws SerializationException {
        List<Map<String, Object>> effects = new ArrayList<>(ef.length);

        for (PotionEffect effect : ef) {
            effects.add(effect.serialize());
        }

        return JSONValue.toJSONString(effects).getBytes();
    }

    public static PotionEffect[] deserializePotionEffects(byte[] b) throws SerializationException, ParseException {
        if (b == null) {
            return null;
        }
        Object o = JSONValue.parseWithException(new String(b));
        try {
            if (o instanceof List) {
                final List<?> data = (List) o;
                ArrayList<PotionEffect> items = new ArrayList<>(data.size());
                for (Object t : data) {
                    if (t instanceof Map) {
                        final Map<?, ?> mdata = (Map) t;
                        final Map<String, Object> conv = new HashMap<>(mdata.size());
                        for (Map.Entry<?, ?> e : mdata.entrySet()) {
                            conv.put(String.valueOf(e.getKey()), convert(e.getValue()));
                        }
                        items.add(new PotionEffect(conv));
                    } else {
                        throw new IllegalArgumentException("Not a Map");
                    }
                }
                return items.toArray(new PotionEffect[items.size()]);
            }
            throw new IllegalArgumentException("Not a List");
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    private static Object convert(Object o) {
        if (o instanceof Number) {
            Long v = (Long) o;
            if (Integer.MAX_VALUE > v) {
                return v.intValue();
            }
        }
        return o;
    }

    private static final NBTTagCompound toTag(String jsonString) throws IOException {
        try {
            return (NBTTagCompound) javaTypeToNBTTag(new JSONParser().parse(jsonString));
        } catch (ParseException e) {
            throw new IOException(e);
        }
    }

    private static final NBTBase javaTypeToNBTTag(Object object) throws IOException {
        // Handle compounds
        if (object instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, ?> map = (Map<String, ?>) object;
            NBTTagCompound tag = new NBTTagCompound();
            for (Entry<String, ?> entry : map.entrySet()) {
                tag.set(entry.getKey(), javaTypeToNBTTag(entry.getValue()));
            }
            return tag;
        }
        // Handle numbers
        if (object instanceof Number) {
            Number number = (Number) object;
            if (number.longValue() == number.doubleValue()) {
                // Whole number
                if (number.intValue() == number.longValue()) {
                    // Fits in integer
                    return new NBTTagInt(number.intValue());
                }
                return new NBTTagLong(number.longValue());
            } else {
                return new NBTTagDouble(number.doubleValue());
            }
        }
        // Handle strings
        if (object instanceof String) {
            return new NBTTagString((String) object);
        }
        // Handle lists
        if (object instanceof List) {
            List<?> list = (List<?>) object;
            NBTTagList listTag = new NBTTagList();

            // Handle int arrays
            if (list.size() > 0) {
                Object firstElement = list.get(0);
                if (firstElement instanceof Number) {
                    @SuppressWarnings("unchecked")
                    List<Number> intList = (List<Number>) list;
                    return new NBTTagIntArray(unboxIntegers(intList));
                }
            }

            for (Object entry : list) {
                listTag.add(javaTypeToNBTTag(entry));
            }
            return listTag;
        }
        throw new IOException("Unknown object: (" + object.getClass() + ") " + object + "");
    }

    private static final int[] unboxIntegers(List<Number> boxed) {
        int[] ints = new int[boxed.size()];
        for (int i = 0; i < ints.length; i++) {
            ints[i] = boxed.get(i).intValue();
        }
        return ints;
    }

    private static final Map<String, Object> toMap(NBTTagCompound tagCompound) throws IOException {
        @SuppressWarnings("unchecked")
        Collection<String> tagNames = tagCompound.c();

        // Add all children
        Map<String, Object> jsonObject = new HashMap<>(tagNames.size());
        for (String subTagName : tagNames) {
            NBTBase subTag = tagCompound.get(subTagName);
            jsonObject.put(subTagName, nbtTagToJavaType(subTag));
        }
        return jsonObject;
    }

    private static final Object nbtTagToJavaType(NBTBase tag) throws IOException {
        if (tag instanceof NBTTagCompound) {
            return toMap((NBTTagCompound) tag);
        } else if (tag instanceof NBTTagList) {
            // Add all children
            NBTTagList listTag = (NBTTagList) tag;
            List<Object> objects = new ArrayList<>();
            for (int i = 0; i < listTag.size(); i++) {
                objects.add(tagInNBTListToJavaType(listTag, i));
            }
            return objects;
        } else if (tag instanceof NBTNumber) {
            // Check if double or long
            NBTNumber nbtNumber = (NBTNumber) tag;
            if (nbtNumber.c() == nbtNumber.g()) {
                // Long, as double value == long value
                return nbtNumber.c();
            } else {
                // Double
                return nbtNumber.g();
            }
        } else if (tag instanceof NBTTagString) {
            String value = ((NBTTagString) tag).a_();
            return value;
        } else if (tag instanceof NBTTagByteArray) {
            return boxBytes(((NBTTagByteArray) tag).c());
        } else if (tag instanceof NBTTagIntArray) {
            return boxIntegers(((NBTTagIntArray) tag).c());
        }

        throw new IOException("Unknown tag: " + tag);
    }

    private static final List<Byte> boxBytes(byte[] byteArray) {
        List<Byte> byteList = new ArrayList<>(byteArray.length);
        for (byte aByte : byteArray) {
            byteList.add(aByte); // Wraps
        }
        return byteList;
    }

    private static final List<Integer> boxIntegers(int[] intArray) {
        List<Integer> integerList = new ArrayList<>(intArray.length);
        for (int anInt : intArray) {
            integerList.add(anInt); // Wraps
        }
        return integerList;
    }

    private static final Object tagInNBTListToJavaType(NBTTagList tagList, int position) throws IOException {
        switch (tagList.d()) {
        case 10:
            NBTTagCompound compoundValue = tagList.get(position);
            return nbtTagToJavaType(compoundValue);
        case 11:
            return boxIntegers(tagList.c(position));
        case 6:
            double doubleValue = tagList.d(position);
            return doubleValue;
        case 5:
            float floatValue = tagList.e(position);
            return floatValue;
        case 8:
            String stringValue = tagList.getString(position);
            return stringValue;
        }
        throw new IOException("Unknown list: " + tagList);
    }

}