package com.minelittlepony.unicopia.util; import java.util.*; import java.util.function.*; import java.util.stream.Collectors; import java.util.stream.Stream; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import net.minecraft.item.ItemStack; import net.minecraft.nbt.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; public interface NbtSerialisable { Serializer BLOCK_POS = Serializer.of(NbtHelper::toBlockPos, NbtHelper::fromBlockPos); Serializer ITEM_STACK = Serializer.of(ItemStack::fromNbt, stack -> stack.writeNbt(new NbtCompound())); /** * Called to save this to nbt to persist state on file or to transmit over the network * * @param compound Compound tag to write to. */ void toNBT(NbtCompound compound); /** * Called to load this state from nbt * * @param compound Compound tag to read from. */ void fromNBT(NbtCompound compound); default NbtCompound toNBT() { NbtCompound compound = new NbtCompound(); toNBT(compound); return compound; } static NbtList writeVector(Vec3d vector) { NbtList list = new NbtList(); list.add(NbtDouble.of(vector.getX())); list.add(NbtDouble.of(vector.getY())); list.add(NbtDouble.of(vector.getZ())); return list; } static Vec3d readVector(NbtList list) { return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2)); } static Optional decode(Codec codec, NbtElement nbt) { return codec.decode(NbtOps.INSTANCE, nbt).result().map(Pair::getFirst); } static NbtElement encode(Codec codec, T value) { return codec.encodeStart(NbtOps.INSTANCE, value).result().get(); } static NbtCompound subTag(String name, NbtCompound parent) { NbtCompound child = new NbtCompound(); parent.put(name, child); return child; } static NbtCompound subTag(String name, NbtCompound parent, Consumer writer) { writer.accept(subTag(name, parent)); return parent; } static Map readMap(NbtCompound nbt, Function keyFunction, Function valueFunction) { return readMap(nbt, keyFunction, (k, v) -> valueFunction.apply(v)); } static Map readMap(NbtCompound nbt, Function keyFunction, BiFunction valueFunction) { return nbt.getKeys().stream().map(k -> { K key = keyFunction.apply(k); if (key == null) { return null; } V value = valueFunction.apply(key, nbt.get(k)); if (value == null) { return null; } return Map.entry(key, value); }) .filter(Objects::nonNull) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } static NbtCompound writeMap(Map map, Function keyFunction, Function valueFunction) { return writeMap(new NbtCompound(), map, keyFunction, valueFunction); } static NbtCompound writeMap(NbtCompound nbt, Map map, Function keyFunction, Function valueFunction) { map.forEach((k, v) -> nbt.put(keyFunction.apply(k), valueFunction.apply(v))); return nbt; } interface Serializer { T read(NbtCompound compound); NbtCompound write(T t); default Optional readOptional(String name, NbtCompound compound) { return compound.contains(name, NbtElement.COMPOUND_TYPE) ? Optional.ofNullable(read(compound.getCompound(name))) : Optional.empty(); } default void writeOptional(String name, NbtCompound compound, Optional t) { t.map(this::write).ifPresent(tag -> compound.put(name, tag)); } default T read(NbtElement element) { return read((NbtCompound)element); } default NbtList writeAll(Collection ts) { NbtList list = new NbtList(); ts.stream().map(this::write).forEach(list::add); return list; } default Stream readAll(NbtList list) { return list.stream().map(this::read).filter(Objects::nonNull); } static Serializer of(Supplier factory) { return of(nbt -> { T value = factory.get(); value.fromNBT(nbt); return value; }, value -> value.toNBT()); } static Serializer of(Function read, Function write) { return new Serializer<>() { @Override public T read(NbtCompound compound) { return read.apply(compound); } @Override public NbtCompound write(T t) { return write.apply(t); } }; } } }