package de.take_weiland.mods.commons.nbt;
import de.take_weiland.mods.commons.util.Blocks;
import de.take_weiland.mods.commons.util.Items;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.*;
import net.minecraftforge.fluids.FluidStack;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.UUID;
/**
* @author diesieben07
*/
public final class NBTData {
public static final byte NULL = -1;
public static final String NULL_KEY = "_sc$null";
private NBTData() { }
/**
* <p>Write the given String to NBT.</p>
* @param s the String
* @return NBT data
*/
@Nonnull
public static NBTBase writeString(@Nullable String s) {
return s == null ? serializedNull() : new NBTTagString("", s);
}
/**
* <p>Read a String from NBT.</p>
* @param nbt the NBT data
* @return a String
*/
@Nullable
public static String readString(@Nullable NBTBase nbt) {
return isSerializedNull(nbt) ? null : ((NBTTagString) nbt).data;
}
@Nonnull
public static NBTBase writeBlock(@Nullable Block block) {
if (block == null) {
return serializedNull();
} else {
return new NBTTagShort("", (short) block.blockID);
}
}
@Nullable
public static Block readBlock(@Nullable NBTBase nbt) {
if (isSerializedNull(nbt)) {
return null;
} else {
return Blocks.byID(((NBTTagShort) nbt).data);
}
}
@Nonnull
public static NBTBase writeItem(@Nullable Item item) {
if (item == null) {
return serializedNull();
} else {
return new NBTTagShort("", (short) item.itemID);
}
}
@Nullable
public static Item readItem(@Nullable NBTBase nbt) {
if (isSerializedNull(nbt)) {
return null;
} else {
return Items.byID(((NBTTagShort) nbt).data);
}
}
/**
* <p>Write the given UUID to NBT.</p>
* @param uuid the UUID
* @return NBT data
*/
@Nonnull
public static NBTBase writeUUID(@Nullable UUID uuid) {
if (uuid == null) {
return serializedNull();
} else {
NBTTagList nbt = new NBTTagList();
nbt.appendTag(new NBTTagLong("", uuid.getMostSignificantBits()));
nbt.appendTag(new NBTTagLong("", uuid.getLeastSignificantBits()));
return nbt;
}
}
/**
* <p>Read an UUID from NBT.</p>
* @param nbt the NBT data
* @return an UUID
*/
@Nullable
public static UUID readUUID(@Nullable NBTBase nbt) {
if (isSerializedNull(nbt) || nbt.getId() != NBT.TAG_LIST) {
return null;
} else {
NBTTagList list = (NBTTagList) nbt;
return new UUID(((NBTTagLong) list.tagAt(0)).data, ((NBTTagLong) list.tagAt(1)).data);
}
}
/**
* <p>Write the given ItemStack to NBT.</p>
* @param stack the ItemStack
* @return NBT data
*/
@Nonnull
public static NBTBase writeItemStack(@Nullable ItemStack stack) {
return stack == null ? serializedNull() : stack.writeToNBT(new NBTTagCompound());
}
/**
* <p>Read an ItemStack from NBT.</p>
* @param nbt the NBT data
* @return an ItemStack
*/
@Nullable
public static ItemStack readItemStack(@Nullable NBTBase nbt) {
return isSerializedNull(nbt) ? null : ItemStack.loadItemStackFromNBT((NBTTagCompound) nbt);
}
/**
* <p>Write the given FluidStack to NBT.</p>
* @param stack the FluidStack
* @return NBT data
*/
@Nonnull
public static NBTBase writeFluidStack(@Nullable FluidStack stack) {
return stack == null ? serializedNull() : stack.writeToNBT(new NBTTagCompound());
}
/**
* <p>Read a FluidStack from NBT.</p>
* @param nbt the NBT data
* @return a FluidStack
*/
@Nullable
public static FluidStack readFluidStack(@Nullable NBTBase nbt) {
return isSerializedNull(nbt) ? null : FluidStack.loadFluidStackFromNBT((NBTTagCompound) nbt);
}
/**
* <p>Write the given Enum to NBT.</p>
* @param e the Enum
* @return NBT data
*/
@Nonnull
public static <E extends Enum<E>> NBTBase writeEnum(@Nullable E e) {
if (e == null) {
return serializedNull();
} else {
return new NBTTagString("", e.name());
}
}
/**
* <p>Read an Enum of the given Class from NBT.</p>
* @param nbt the NBT data
* @param clazz the Class of the Enum to read
* @return an Enum
*/
@Nullable
public static <E extends Enum<E>> E readEnum(@Nullable NBTBase nbt, Class<E> clazz) {
if (isSerializedNull(nbt)) {
return null;
} else {
return Enum.valueOf(clazz, ((NBTTagString) nbt).data);
}
}
@Nonnull
public static <E extends Enum<E>> NBTBase writeEnumSet(@Nullable EnumSet<E> enumSet) {
if (enumSet == null) {
return serializedNull();
} else {
NBTTagList list = new NBTTagList();
for (E e : enumSet) {
list.appendTag(new NBTTagString("", e.name()));
}
return list;
}
}
@Nullable
public static <E extends Enum<E>> EnumSet<E> readEnumSet(@Nullable NBTBase nbt, Class<E> enumClass) {
if (isSerializedNull(nbt)) {
return null;
} else {
EnumSet<E> enumSet = EnumSet.noneOf(enumClass);
NBTTagList list = (NBTTagList) nbt;
for (int i = 0, len = list.tagCount(); i < len; i++) {
enumSet.add(Enum.valueOf(enumClass, ((NBTTagString) list.tagAt(i)).data));
}
return enumSet;
}
}
@Nonnull
public static NBTBase writeBitSet(@Nullable BitSet bitSet) {
if (bitSet == null) {
return serializedNull();
} else {
return new NBTTagByteArray("", bitSet.toByteArray());
}
}
@Nullable
public static BitSet readBitSet(@Nullable NBTBase nbt) {
if (isSerializedNull(nbt)) {
return null;
} else {
return BitSet.valueOf(((NBTTagByteArray) nbt).byteArray);
}
}
/**
* <p>Get an NBT Tag that represents {@code null}.</p>
* @return NBT data
* @see #isSerializedNull(net.minecraft.nbt.NBTBase)
*/
@Nonnull
public static NBTBase serializedNull() {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setByte(NULL_KEY, NULL);
return nbt;
}
/**
* <p>Check if the given NBT Tag is null or represents a serialized {@code null} reference.</p>
* @param nbt the NBT data
* @return true if the NBT data represents null
* @see #serializedNull()
*/
@Contract("null->true")
public static boolean isSerializedNull(@Nullable NBTBase nbt) {
return nbt == null || nbt.getId() == NBT.TAG_COMPOUND && ((NBTTagCompound) nbt).getByte(NULL_KEY) == NULL;
}
}