Search Unity

SerializeUtilityHybrid and SharedComponentData Questions

Discussion in 'Entity Component System' started by slims, Aug 13, 2020.

  1. slims

    slims

    Joined:
    Dec 31, 2013
    Posts:
    86
    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

    Code (CSharp):
    1. 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:

    Code (CSharp):
    1.      
    2. using (var writer = new StreamBinaryWriter(SaveGamePath + fileName + SaveGameExtension))
    3. {
    4.    SerializeUtilityHybrid.Serialize(World.DefaultGameObjectInjectionWorld.EntityManager, writer, out var objRefs);
    5. }
    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:

    Code (CSharp):
    1.       var localWorld = new World("local world");
    2. using (var reader = new StreamBinaryReader(SaveGamePath + fileName + SaveGameExtension))
    3. {
    4.   SerializeUtilityHybrid.Deserialize(localWorld.EntityManager, reader, null);
    5. }
    6.  
    7. 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.
     
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    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.
     
  3. slims

    slims

    Joined:
    Dec 31, 2013
    Posts:
    86
    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.
     
  4. BackgroundMover

    BackgroundMover

    Joined:
    May 9, 2015
    Posts:
    224
    Last edited: Aug 14, 2020
  5. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    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.
     
  6. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,266
    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.
     
    BackgroundMover likes this.