Entites losing references when moved between worlds

Hey Guys,

Im working with serializing and deserializing and its been a touch ride but I think I’m right at the finish line, there seems to be just one more thing I need some help figuring out.

Im running into some issues with moving entities between worlds to only serialize what I want. Here is my code to save what I want seralized.

private void SaveWorld()
        {
            EntityManager.RemoveComponent<SceneTag>(EntityManager.UniversalQuery);
            object[] unityMappingTable;

            EntityQuery seralizableQuery = EntityManager.CreateEntityQuery(typeof(Seralizable));
            World localWorld = new World("local world");
            localWorld.EntityManager.MoveEntitiesFrom(EntityManager, seralizableQuery);

            using (StreamBinaryWriter writer = new StreamBinaryWriter(Application.persistentDataPath + "/gameSave.dat"))
            {
                SerializeUtility.SerializeWorld(localWorld.EntityManager, writer, out unityMappingTable);
            }

            using (StreamWriter writer = new StreamWriter(Application.persistentDataPath + "/objects.dat", false))
            {
                for (int i = 0; i < unityMappingTable.Length; i++)
                {
                    writer.WriteLine(unityMappingTable[i]);
                }
            }

            EntityManager.MoveEntitiesFrom(localWorld.EntityManager, localWorld.EntityManager.UniversalQuery);
        }

When I run this however my entities come back to the main world with a bunch of fields like sprites and materials set to Entity.Null

In some of my learning with serialization it seems like a problem similar to the mappingTable returned. I have also been looking into the EntityRemapUtility but my attempts to use it have not been fruitful thus far.

Any advice is much appreciated.

Thanks in advance!

You can’t serialize or save to disk UnityEngine.Object like that. You can only store Unity objects on disk using asset containers they provide, like ScriptableObject. And you can only save assets to disk in the editor not in a build.

Unity’s hybrid serialization and sub scenes store the objects in ReferencedUnityObjects which is an SO just for that purpose. But it’s a design time construct.

So you need to start by using sub scenes or SerializeHybridUtility and create entity prefabs at design time. From there the best approaches get somewhat context specific.

For a save game state scenario you can only serialize/save data only. That restriction has a number of implications. You have to reconstruct your data from some combination of entity prefabs and your save state. If you have a lot of hierarchy and/or don’t have clean separation between render entities and other entities that have related data, reconstruction can get more complex.

I would just save instance specific data and then restore would instantiate entity prefabs and patch them with the instance data. That instance data could be entities/components themselves, or something more custom you just save using binary serialization.

1 Like

The serialization is not a problem, that just writes the asset names to the disk for example “circle (UnityEngine.Sprite)” and then im using addressables to map that to an asset. I was originally trying to seralize the whole world and then remove all duplicate entities to prevent singleton confusion but since you arent able to access “WorldTime” I couldn’t figure out how to remove that one and I was forced to do it a more proper way. Anyway the serialization works and I can get my assets back displaying on the screen.

What this post is about is transferring entities between worlds. When I move entities to another world they are losing their references to other entities.

I ended up figuring out the solution, I needed to move all the entities over together in on big query

EntityQueryDesc seralizableQuery = new EntityQueryDesc { All = new ComponentType[] { typeof(Seralizable) } };
            EntityQueryDesc pocketManagerQuery = new EntityQueryDesc { All = new ComponentType[] { typeof(PocketManager) } };
            EntityQueryDesc spriteRenderDataQuery = new EntityQueryDesc { All = new ComponentType[] { typeof(SpriteRenderData) } };
            EntityQueryDesc spriteRenderer = new EntityQueryDesc { All = new ComponentType[] { typeof(Unity.U2D.Entities.SpriteRenderer) } };
            var componentTypes = new NativeArray<ComponentType>();
            EntityManager em = EntityManager;
            Entities.WithAll<Unity.U2D.Entities.SpriteRenderer>().ForEach((in Entity entity, in Unity.U2D.Entities.SpriteRenderer spriteRenderer1) =>
            {
                componentTypes = em.GetComponentTypes(spriteRenderer1.Material);

            }).Run();
            EntityQueryDesc materialQuery = new EntityQueryDesc { All = componentTypes.ToArray() };
            componentTypes.Dispose();

            EntityQueryDesc[] combinedQuery = new EntityQueryDesc[] { seralizableQuery, pocketManagerQuery, spriteRenderDataQuery, materialQuery };

            EntityQuery query = EntityManager.CreateEntityQuery(combinedQuery);
            World localWorld = new World("local world");
            localWorld.EntityManager.MoveEntitiesFrom(EntityManager, query);