SerializeUtilityHybrid and SharedComponentData Questions

I’m struggling to get the SerializeUtilityHybrid working the way I want.

I don’t want to worry about SharedComponentData, I’m only concerned with actual game state, but it seems like the Deserialize method requires at least some SharedComponentData or else it throws this error:

ArgumentException: We are reading a UnityEngine.Object however no ObjectTable was provided to the ManagedObjectBinaryReader.

Basically the method

Unity.Serialization.Binary.Adapters.Contravariant.IBinaryAdapter<UnityEngine.Object>.Deserialize

Forces you to have passed in at least 1 object, otherwise it will throw errors.

Here’s how I’m serializing:

using (var writer = new StreamBinaryWriter(SaveGamePath + fileName + SaveGameExtension))
{
   SerializeUtilityHybrid.Serialize(World.DefaultGameObjectInjectionWorld.EntityManager, writer, out var objRefs);
}

I do nothing with obj refs, since it’s all mesh data that doesn’t need to be saved with game state.

The errors get thrown in when Deserialize gets called in my code here:

      var localWorld = new World("local world");
using (var reader = new StreamBinaryReader(SaveGamePath + fileName + SaveGameExtension))
{
  SerializeUtilityHybrid.Deserialize(localWorld.EntityManager, reader, null);
}

World.DefaultGameObjectInjectionWorld.EntityManager.MoveEntitiesFrom(localWorld.EntityManager);

Note that I’ve tried passing in a ReferencedUnityObjects with an empty array in addition to passing null in here.

And I guess the natural follow up to this is what is the best practice to putting back shared component data after deserialization? Am I going to just have to recreate all the deserialized entities and copy their data over? I really don’t want to have to serialize stuff like mesh data, since clients should be able to deal with that on their own.

I haven’t looked recently to see what new tools might be there that simplify/optimize what the lower level approach is, so you might want to just dig through the source a bit.

So the starting point would be entity prefabs. You save only the data you need and that will automatically exclude shared components and also blob assets. Because your prefabs already have those and they are already loaded. if you aren’t using entity prefabs you need to fix that first.

Restore is then a process of load your state data. Then for each state instantiate a prefab and overwrite the instantiated entity with restored state as appropriate. You could also do the instantiation in a batch and then use a changed filter and do the actual state restoration in a job. Probably a few ways to optimize this flow.

The lowest common denominator for saving your state would be lower level binary serialization. Like an array per entity archetype with your own custom struct wrapper per archetype.

Are you suggesting I manually serialize without using the SerializeUtilityHybrid? Basically iterate over entity prefabs to determine the composition of stuff I need to load, serialize it, then deserialize it all on load, instantiating entity prefabs and copying over the deserialized data to them?

I was hoping to avoid a big manual process, since this utility seems to do exactly what I want it to without extra code. The problem is just that it’s demanding deserialization of SharedComponentData.

I think its just demanding that you feed it a valid object of the managed type that was on the entity prefab.

but it sounds like high level serialization is still being worked on
https://discussions.unity.com/t/800700/3

SerializeHybridUtility is as the name implies designed to serialize hybrid. It was designed for conversion mainly.

You asked for best practices. Best practice here is not simple, it has to account for things like data migration, space optimization etc… In production games significant work goes into data migration flows.

If you want quick and dirty there might be some newer api’s that support closer to what you want then the lower level binary serialization stuff. Or some hacks you can find to force stuff to work. I’m just not aware of any off the top of my head.

If your goal is to avoid serializing large assets, I would suggest running some systems on your data that swap out RenderMesh and friends with replacement components that contain FixedStrings to assets or something. Then you can serialize everything and invert the process when you deserialize.

1 Like