Search Unity

How to deserialize a world with SharedComponents?

Discussion in 'Entity Component System' started by mkracik, Nov 4, 2018.

  1. mkracik

    mkracik

    Joined:
    Aug 5, 2018
    Posts:
    17
    The old examples no longer work, there are now additional parameters:
    SerializeWorld(EntityManager entityManager, BinaryWriter writer, out int[] sharedComponentsToSerialize)
    DeserializeWorld(ExclusiveEntityTransaction manager, BinaryReader reader, int numSharedComponents)

    I have a simple scene with 2 MeshInstanceRenderers which are SharedComponents, my code is:

    Code (CSharp):
    1. private void SaveWorld()
    2. {
    3.     EntityManager entityManager = World.Active.GetOrCreateManager<EntityManager>();
    4.  
    5.     using (Unity.Entities.Serialization.BinaryWriter writer = new StreamBinaryWriter(savedWorldFilename))
    6.     {
    7.         int[] sharedComponents;
    8.         SerializeUtility.SerializeWorld(entityManager, writer, out sharedComponents);
    9.     }
    10. }
    11.  
    12. private void LoadWorld()
    13. {
    14.     EntityManager entityManager = World.Active.GetOrCreateManager<EntityManager>();
    15.  
    16.     using (Unity.Entities.Serialization.BinaryReader reader = new StreamBinaryReader(savedWorldFilename))
    17.     {
    18.         using (World tempWorld = new World("loading"))
    19.         {
    20.             EntityManager e2 = tempWorld.GetOrCreateManager<EntityManager>();
    21.  
    22.             SerializeUtility.DeserializeWorld(e2.BeginExclusiveEntityTransaction(), reader, 2);
    23.             e2.EndExclusiveEntityTransaction();
    24.  
    25.             entityManager.MoveEntitiesFrom(e2);
    26.         }
    27.     }
    28. }
    29.  
    From SerializeWorld I get out int[] sharedComponents = {2, 1}. Do I need to do some additional steps here?

    No matter what I pass to DeserializeWorld as parameter numSharedComponents, I always get an error (I tried 0, 1, 2).

    NullReferenceException: Object reference not set to an instance of an object
    Unity.Entities.EntityDataManager.TryRemoveEntityId (Unity.Entities.Entity* entities, System.Int32 count, Unity.Entities.ArchetypeManager archetypeManager, Unity.Entities.SharedComponentDataManager sharedComponentDataManager, Unity.Entities.EntityGroupManager groupManager, Unity.Entities.ComponentTypeInArchetype* componentTypeInArchetypeArray) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/EntityDataManager.cs:896)
    Unity.Entities.EntityManager.DestroyEntityInternal (Unity.Entities.Entity* entities, System.Int32 count) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/EntityManager.cs:341)
    Unity.Entities.EntityManager.DestroyEntity (Unity.Collections.NativeArray`1[T] entities) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/EntityManager.cs:324)
    Unity.Entities.EntityManager.OnDestroyManager () (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/EntityManager.cs:204)
    Unity.Entities.ScriptBehaviourManager.DestroyInstance () (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/ScriptBehaviourManager.cs:41)
    Unity.Entities.World.Dispose () (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/Injection/World.cs:73)
    UnityEngine.Debug:LogException(Exception)
    Unity.Debug:LogException(Exception) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/Stubs/Unity/Debug.cs:25)
    Unity.Entities.World:Dispose() (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/Injection/World.cs:77)
    BootTime:LoadWorld() (at Assets/Code/BootTime/BootTime.cs:71)
    BootTime:Update() (at Assets/Code/BootTime/BootTime.cs:50)

    IndexOutOfRangeException: Index 1 is out of range in NativeList of '1' Length.
    Unity.Collections.NativeListImpl`3[T,TMemManager,TSentinel].get_Item (System.Int32 index) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.collections@0.0.9-preview.9/Unity.Collections/NativeListImpl.cs:57)
    Unity.Collections.NativeList`1[T].get_Item (System.Int32 index) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.collections@0.0.9-preview.9/Unity.Collections/NativeList.cs:49)
    Unity.Entities.SharedComponentDataManager.AddReference (System.Int32 index) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/SharedComponentManager.cs:215)
    Unity.Entities.ArchetypeManager.AddExistingChunk (Unity.Entities.Chunk* chunk) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/ArchetypeManager.cs:685)
    Unity.Entities.ExclusiveEntityTransaction.AddExistingChunk (Unity.Entities.Chunk* chunk) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/ExclusiveEntityTransaction.cs:276)
    Unity.Entities.Serialization.SerializeUtility.DeserializeWorld (Unity.Entities.ExclusiveEntityTransaction manager, Unity.Entities.Serialization.BinaryReader reader, System.Int32 numSharedComponents) (at C:/Users/Michal/AppData/Local/Unity/cache/packages/staging-packages.unity.com/com.unity.entities@0.0.12-preview.19/Unity.Entities/SerializeUtility.cs:89)
    BootTime.LoadWorld () (at Assets/Code/BootTime/BootTime.cs:75)
    BootTime.Update () (at Assets/Code/BootTime/BootTime.cs:50)
     
  2. simonm_unity

    simonm_unity

    Unity Technologies

    Joined:
    Mar 21, 2018
    Posts:
    13
    Hi,
    In order for SerializeUtility.DeserializeWorld to work the needed shared components must be inserted into the world before it called.
    When using shared components it's easier to use SerializeUtilityHybrid.Serialize / Deserialize. These functions add the shared component values as components on a GameObject which then needs to be serialized / deserialized separately (for example in a prefab).
    The reason for this is that the binary entity file format doesn't support managed objects.
    Would this approach work for your use case?
     
    eizenhorn likes this.
  3. mkracik

    mkracik

    Joined:
    Aug 5, 2018
    Posts:
    17
    OK, so I can use SerializeUtilityHybrid.Serialize / Deserialize as in:
    FPSSample/Packages/com.unity.entities/Unity.Entities.Hybrid.Tests/Runtime/SharedComponentSerializeTests.cs

    where sharedComponents stays in memory between Serialize and Deserialize.

    But how can I serialize and deserialize sharedComponents? What do you mean in a prefab? Isn't it available only in the editor, not at runtime?

    Thanks in advance.
     
  4. simonm_unity

    simonm_unity

    Unity Technologies

    Joined:
    Mar 21, 2018
    Posts:
    13
    In the Mega City sample we create a prefab containing the the shared components for each sub scene:
    PrefabUtility.CreatePrefab(prefabPath, sharedComponents, ReplacePrefabOptions.ReplaceNameBased);

    and load them at runtime:
    resourceRequest = Resources.LoadAsync<GameObject>(prefabPath);

    You are right that the creation of the prefab only works in the editor. Does your use case require you to save the scenes at runtime?
     
    eizenhorn likes this.
  5. mkracik

    mkracik

    Joined:
    Aug 5, 2018
    Posts:
    17
    Thank you, that approach worked for me.

    My use case is that I am trying to implement the usual savegame functionality (game save and load). I guess that's possible as long as the SharedComponents (MeshInstanceRenderers) are not changing during runtime and I can write them once into a prefab when the game is running in Unity Editor.
     
  6. ConAim

    ConAim

    Joined:
    Jan 17, 2017
    Posts:
    16
    I would be nice if during Serialize with only selective Entity (with a list of typeof<IComponent> as input). Instead of Serialize the whole World of junks and then late on running so many issues to Deserialize...
     
    TheGabelle likes this.