Search Unity

Serializing Entity References

Discussion in 'Entity Component System' started by orionburcham, Dec 15, 2018.

  1. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    How might one serialize an entity reference?

    In past ECS code (before Unity ECS), I tightly controlled the process of rebuilding entities when loading a saved game, and then rebuilding any entity references that were stored across components.

    In the new Unity ECS architecture, are Entity references serializable? How are devs intended to persist these references in a save file?
     
  2. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    For anyone interested in this:

    I believe Entities in Unity ECS are structs, which are only used as identifiers a when accessing components.

    So if that’s correct, there’s no reference to save. Assuming Entity structs can be serialized in some way, then that’s all you’d need to do.

    The other big assumption here is that Unity will let you recreate an entity with the same exact Entity ID value when loading saved game data. If they don’t, then none of the Entity IDs you saved will actually relate to anything. That would be trickier.
     
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    This functionality is already there in the serialize API. It requires you to move everything to a separated world. When you move them, the entities are being remapped so that it fits the new world. On serialize, they are once again remapped to the serialized file (unique only in the file, reset back to ID 1 2 3 ..) The remap looks through all your Entity field in IComponentData recursively, so all references are properly saved. On deserialize back, you again need a fresh world so they have no problem about conflicting index. On moving from your load world to main world, they would all be remapped so that the index goes after what's already been used in that world.

    *edit : https://gametorrahod.com/unity-ecs-serializing-ecs-data-252231e5b16d#2b04
     
    eterlan, The5 and orionburcham like this.
  4. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    Thank you very much for the info! Your blog post is excellent!

    Just one more question: What you described should work to serialize/deserialize entities created completely at runtime. But what about entities that are based on scene objects?

    Let's say your game involves cleaning up a house. In a scene representing the house, you lay out the furniture and clutter exactly as you'd like. Then at runtime, the scene is loaded, and the player can move or clean various entities in the house. However, the player can save their progress at any time, and load it back later.

    In a case like that, the serialized Entity values in the save file would seemingly need to match up to persistent Entity IDs for each object in the scene. When loading the save file, first you'd load the scene, then you'd deserialize the saved data, and re-alter the house objects based on their Entity IDs.

    I've solved this problem in other ECS engines, and I can speak to that implementation if it would be helpful. How does Unity ECS solve this problem? Thank you for any advice!
     
    Last edited: Dec 15, 2018
  5. Given the speed of the ECS, I think it's cheap enough to trash the current scene objects and recreate everything from the save rather than starting to fiddle around and trying to match up the file serialized items with the ones in the scene. It's not like you need to destroy and recreate the assets because those aren't part of the entities. See the MegaCity demo when they are using worlds to stream parts of the city, same task with a slightly different purpose.
     
  6. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    Without persistent IDs, how would you even know which scene objects to trash?

    I’ve solved this in the past by assigning each mutable scene object a persistent ID. That ID could then be saved in a save file, along with any changes.

    But all Unity ECS IDs seem to be generated at runtime. How would you even know which Scene Objects to destroy, when loading your save?
     
  7. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Here's the completely ECS way, you don't need to have any Entity reference because it works on its own. Supposed you have 3 kinds of scene object : Chair, Desk, and Bulb.

    One Entity would have ChairComponent/DeskComponent/BulbComponent along with Position/Rotation/Scale (PRS) component. These goes in the save file.

    In the scene they would be added with MeshInstanceRenderer (MIR) component so they can render a model based on its PRS. MeshInstanceRenderer will get assigned the correct mesh and materials based on whether it has Chair Desk or Bulb at that time.

    Player can change PRS to move these objects. Destroying the entity would make the object disappear because MIR and PRS also got destroyed.

    Before saving strip off MIR component. When load back MIR would be reattached again automatically. This way there is no "scene object"
     
    eterlan and The5 like this.
  8. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    If there are no scene objects, then how can an artist place things by hand in the house?
     
  9. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    You mean in the Unity editor? Because ECS is still lacking proper editor integration, the way now is to go hybrid with GameObjectEntity and wrappers + edit mode systems. Various transform and rendering related systems has [ExecuteInEditMode], and with at least 1 GOE present in the scene would automatically request an editor world for those systems.

    To use Unity gizmo, the gizmo updates the normal Transform component. You then use CopyTransformFromGameObject component attached to send those values to its own PRS. (Though currently it does not copy Scale, I had to write a custom system which updates scale too). PRS can be preattached with its wrapper counterpart (__Component). You may change PRS wrapper values in the inspector directly too and you don't need the copy component and copy system running anymore.

    Once those values are in PRS, it's ECS from there including rendering.
     
  10. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    I truly appreciate your help in this thread. At the same time, I don’t think I’m doing a good job of getting my question across:

    Even with a hybrid approach, or better ECS editor integration, how would you accomplish the following:

    1. your game is about cleaning a house.
    2. Artists on your team have hand-placed furniture inside the house, in a messy configuration.
    3. At runtime, a player can move or clean that furniture around the house, to put it back in order.
    4. The player can save, and reload, their progress at any time.
    In this scenario, it’s important that the furtniture assets be placed by hand by an artist or level designer.

    It’s also important that the player be able to move and alter those same objects, and for those changes to be saveable and loadable.

    We must also allow for the possibility that, post launch, an artist may need to go into the scene file and change a chair’s starting position (for example, the chair’s original position could cause pathing problems). The chair’s new position would be pushed in a patch, and players who had not already moved that chair in their saved game would now see the chair’s new position when they load their progress.

    This is a very common real-world scenario from past projects I’ve worked on.

    - - -

    So without being able to assign persistent Entity IDs to scene objects, and to then be able to serialize those same exact Entities when making your saved game, how could the above example be done?

    Thank you for any insight.
     
    Last edited: Dec 16, 2018
  11. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    In that case then you must create your own ID system, because basically each of your objects is "named". Entity cannot be used as a fixed name, one bootstrap-style system which create an entity before you can create your furniture would offset everything.

    To the original question, Entity is serializable and any inter-Entity connection will be preserved. But Entity is not for GUID-like task in the first place.
     
    eterlan likes this.