Serializing world data, loading from disk, and pasting back to the world

I’m attempting to write a plugin to store structure data for the world, then be able to output those structures at certain points (with timed construction) for possible PVP games or Tower Defense mini games.

I’ve gotten to the point in my plugin where I am capable of storing the data for the block using MessagePack into a 3D String array holding the data from each Location.getBlock().toString() and retrieving that data from a “.struct” file (Proprietarily created by me).

The issue I’m running into now is: I have the entires of “minecraft:{blocktype}[key=value]” for each position in the array but from there, how do I actually transform that data into usable objects to apply to BlockStates, etc.?
Also, how do I even apply those objects to the BlockState. I know I can use the registry to do: game.getRegistry().getType(BlockType.class, “minecraft:{whatever_type}”);
So, I can set the BlockType but nothing else like the position it’s facing, if grass is snowy, or anything else.
I don’t see any methods for set{Value}({object});.
I only see the method “with” to apply data.

TL;DR: I can set BlockType, how do I set the other state variables of blocks?

Thanks for taking the time to read this jumbled post. :yum:

Don’t use toString(), that’s for human representation. use toContainer() to get a DataContainer for the data. That can then be serialized into a variety of formats.

You can reconstruct the object given a DataContainer by using the appropriate builder obtained from the GameRegistry

Okay, so I feel a bit incompetent in this but, I’ve been delving through the documentation for the past few hours with this and haven’t been able to figure it out.

I have figured out the extraction of:
DataContainer container = location.getBlock().toContainer();
container.getInt(new DataQuery(“UnsafeMeta”)).orElse(0) --> For the metadata (grassy, snowy, whatever)
contianer.getString(new DataQuery(“BlockType”)).orElse(“minecraft:air”) --> For the base block.

(Pretending I’ve stored this and pulled back out the BlockType string and the UnsafeMeta string.)

Now, I’ve also figured out that you can obtain the BlockType with:
BlockType t =
(BlockType) GenericArguments.catalogedElement(Texts.of(“minecraft:whateverIpulledfromthefile”),game,BlockType.class);

Then use:
BlockStateBuilder builder = game.getRegistry().createBlockStateBuilder().blockType(t);

This is where I get stuck.
I can’t figure out how to properly construct a DataManipulator class or whatever I need to apply it to the block.
I’ve tried:
DataContainer dataContainer = new MemoryDataContainer();
dataContainer.set(new DataQuery(“UnsafeMeta”),0);
But then I can’t figure out how to apply that to the block either.

I know I could have just written “I can’t figure out how to apply metadata to a block” but I figured I’d rather show that I’ve been attempting this than leading you to believe I’m wasting your time.

Thank you so much.

Please use schematics + metadata or a variation of bo2 or bo3 data. Your users will love you for it.

I’d strongly recommend avoiding using metadata values and use the BlockTraits instead. This way you can rely on the actual values provided by Minecraft and avoid dealing with the serialization/deserialization of things in Data API that really aren’t supported whatsoever (in this case, grabbing the unsafe data and expecting to reconstruct based on that damage value).

What I would recommend is quite literally serializing the BlockSnapshot.toContainer() and then grabbing the DataBuilder<BlockSnapshot> from the SerializationService and rebuilding said BlockSnapshot.

Could you elaborate a bit on this or show some example code. I’m still a bit confused on how to serialize multiple blocks into one file, retrieve them, then deserialize and build into that class.

1 Like

So, I’ve attempted to serialize:

FileOutputStream fos = new FileOutputStream("block.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(l2.createSnapshot().toContainer());
oos.close();

And I receive:

[16:05:37] [Server thread/INFO]: [java.lang.Throwable$WrappedPrintStream:println:748]: java.io.NotSerializableException: org.spongepowered.api.data.MemoryDataContainer

Now what?

DataContainer does not implement Serializable. You may implement your own DataTranslator or use the existing ConfigurateTranslator to translate the DataContainers into ConfigurationNodes.