DOTS - ECS Worlds entity transfer error (Halp!)

Hello, I am making a loading system for my project and one part of it has to do with transporting entities between worlds. It works correctly, but i get this error: ArgumentException: System.InvalidOperationException: The entity does not exist
Thrown from job: Unity.Entities.EntityCommandBuffer._mono_to_burst_PlaybackChainChunk


Also, trough testing I found out the error is specifically in the tranfer of entities between worlds, in my main script (bellow).


The entire code message:
ArgumentException: System.InvalidOperationException: The entity does not exist
Thrown from job: Unity.Entities.EntityCommandBuffer._mono_to_burst_PlaybackChainChunk
This Exception was thrown from a function compiled with Burst, which has limited exception support. Turn off burst (Jobs → Burst → Enable Compilation) to inspect full exceptions & stacktraces.
EntityCommandBuffer was recorded in WorldLoader and played back in Unity.Entities.EndSimulationEntityCommandBufferSystem.
at (wrapper managed-to-native) System.Object.wrapper_native_000001DB2D3901E0(intptr,intptr,Unity.Entities.EntityComponentStore/ArchetypeChanges&,Unity.Entities.ECBSharedPlaybackState&,intptr,int,int,bool,Unity.Entities.PlaybackPolicy)
at (wrapper delegate-invoke) .invoke_void_intptr_intptr_EntityComponentStore/ArchetypeChanges&_ECBSharedPlaybackState&_intptr_int_int_bool_PlaybackPolicy(intptr,intptr,Unity.Entities.EntityComponentStore/ArchetypeChanges&,Unity.Entities.ECBSharedPlaybackState&,intptr,int,int,bool,Unity.Entities.PlaybackPolicy)
at Unity.Entities.EntityCommandBuffer._forward_mono_PlaybackChainChunk (Unity.Entities.EntityDataAccess
mgr, Unity.Collections.LowLevel.Unsafe.UnsafeList* managedReferenceIndexRemovalCount, Unity.Entities.EntityComponentStore+ArchetypeChanges& archetypeChanges, Unity.Entities.ECBSharedPlaybackState& playbackState, Unity.Entities.ECBChainPlaybackState* chainStates, System.Int32 currentChain, System.Int32 nextChain, System.Boolean isFirstPlayback, Unity.Entities.PlaybackPolicy playbackPolicy) [0x00000] in C:\Users\Tom\Desktop\Unity\Projects\Qilligon\Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\EntityCommandBuffer.interop.gen.cs:88
at Unity.Entities.EntityCommandBuffer.PlaybackChainChunk (Unity.Entities.EntityDataAccess* mgr, Unity.Collections.LowLevel.Unsafe.UnsafeList* managedReferenceIndexRemovalCount, Unity.Entities.EntityComponentStore+ArchetypeChanges& archetypeChanges, Unity.Entities.ECBSharedPlaybackState& playbackState, Unity.Entities.ECBChainPlaybackState* chainStates, System.Int32 currentChain, System.Int32 nextChain, System.Boolean isFirstPlayback, Unity.Entities.PlaybackPolicy playbackPolicy) [0x00007] in C:\Users\Tom\Desktop\Unity\Projects\Qilligon\Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\EntityCommandBuffer.interop.gen.cs:69
at Unity.Entities.EntityCommandBuffer.PlaybackChain (Unity.Entities.EntityDataAccess* mgr, Unity.Collections.LowLevel.Unsafe.UnsafeList* managedReferenceIndexRemovalCount, Unity.Entities.EntityComponentStore+ArchetypeChanges& archetypeChanges, Unity.Entities.ECBSharedPlaybackState& playbackState, Unity.Entities.ECBChainPlaybackState* chainStates, System.Int32 currentChain, System.Int32 nextChain, System.Boolean isFirstPlayback, Unity.Entities.PlaybackPolicy playbackPolicy) [0x000b2] in C:\Users\Tom\Desktop\Unity\Projects\Qilligon\Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\EntityCommandBuffer.cs:1678
at Unity.Entities.EntityCommandBuffer.PlaybackInternal (Unity.Entities.EntityDataAccess* mgr) [0x0030f] in C:\Users\Tom\Desktop\Unity\Projects\Qilligon\Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\EntityCommandBuffer.cs:1502
at Unity.Entities.EntityCommandBuffer.Playback (Unity.Entities.EntityManager mgr) [0x00000] in C:\Users\Tom\Desktop\Unity\Projects\Qilligon\Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\EntityCommandBuffer.cs:1369
at Unity.Entities.EntityCommandBufferSystem.FlushPendingBuffers (System.Boolean playBack) [0x0007f] in C:\Users\Tom\Desktop\Unity\Projects\Qilligon\Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\EntityCommandBufferSystem.cs:225

Unity.Entities.EntityCommandBufferSystem.FlushPendingBuffers (System.Boolean playBack) (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/EntityCommandBufferSystem.cs:292)
Unity.Entities.EntityCommandBufferSystem.OnUpdate () (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/EntityCommandBufferSystem.cs:190)
Unity.Entities.ComponentSystem.Update () (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/ComponentSystem.cs:113)
Unity.Entities.ComponentSystemGroup.UpdateAllSystems () (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/ComponentSystemGroup.cs:435)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/Stubs/Unity/Debug.cs:19)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/ComponentSystemGroup.cs:440)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/ComponentSystemGroup.cs:387)
Unity.Entities.ComponentSystem:Update() (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/ComponentSystem.cs:113)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/ScriptBehaviourUpdateOrder.cs:333)
*

Can anyone explain to me why it happens and how to fix it, please.
Anyway here is my entire code (happy reading trough it :D):


My main code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using System.IO;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Entities;
using Unity.Entities.Serialization;
using Unity.Jobs;
using Unity.Burst;
using static WorldUtils;
using static WorldData;
using static ArchetypeLibrary;

public class WorldLoader : SystemBase
{
    EndSimulationEntityCommandBufferSystem ECBS;

    NativeHashSet<int2> ActiveChunks;
    NativeHashSet<int2> LoadedChunks;
    NativeHashSet<int2> PendingChunks;

    EntityQuery Query;

    protected override void OnCreate()
    {
        ECBS = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();

        ActiveChunks = new NativeHashSet<int2>(1600, Allocator.Persistent);
        LoadedChunks = new NativeHashSet<int2>(1600, Allocator.Persistent);
        PendingChunks = new NativeHashSet<int2>(1600, Allocator.Persistent);
        Query = GetEntityQuery(typeof(PendingSave));
    }

    protected override void OnUpdate()
    {
        ActiveChunks.Clear();

        var activeChunks = ActiveChunks;
        var loadedChunks = LoadedChunks;
        var pendingChunks = PendingChunks;

        var chunkSize = ChunkSize;
        var chunkArchetype = ChunkArchetype();
        var worldSeed = WorldSeed;

        var ECB = ECBS.CreateCommandBuffer();
        var PECB = ECB.AsParallelWriter();

        var saveWorld = FindWorld("SaveWorld");

        //Activate chunks around Loaders
        Entities.ForEach((in Translation translation, in Loader loader) =>
        {
            float2 Position = new float2(translation.Value.x, translation.Value.y);
            int LoadDistance = loader.LoadDistance;

            for (int x = 0; x < LoadDistance; x++)
            {
                for (int y = 0; y < LoadDistance; y++)
                {
                    int2 chunk = GetChunkFromWorld(Position, chunkSize, new float2(0, 0)) - LoadDistance / 2 + new int2(x, y);
                    if (!activeChunks.Contains(chunk))
                    {
                        activeChunks.Add(chunk);
                    }
                }
            }
        }).WithBurst().Schedule();

        //Load and unload chunks and keep track of newly generated
        Job.WithReadOnly(activeChunks).WithCode(() =>
        {
            var activeChunksArray = activeChunks.ToNativeArray(Allocator.Temp);
            for (int i = 0; i < activeChunksArray.Length; i++)
            {
                int2 chunk = activeChunksArray;
                if (!loadedChunks.Contains(chunk))
                {
                    loadedChunks.Add(chunk);
                    pendingChunks.Add(chunk);
                }
            }
            var loadedChunksArray = loadedChunks.ToNativeArray(Allocator.Temp);
            for (int i = loadedChunksArray.Length - 1; i != -1; i--)
            {
                _int2 chunk = loadedChunksArray*;

                if (!activeChunks.Contains(chunk))
                {
                    loadedChunks.Remove(chunk);
                }
            }
        }).WithBurst().Schedule();

        //Generate new chunks
        Job.WithCode(() =>
        {
            var pendingChunksArray = pendingChunks.ToNativeArray(Allocator.Temp);
            for (int i = pendingChunksArray.Length - 1; i != -1; i--)
            {
                _int2 chunk = pendingChunksArray*;

                Entity entity = ECB.CreateEntity(chunkArchetype);
                float2 position = GetTileCenter(GetWorldFromChunk(chunk, chunkSize, new float2(0, 0)), chunkSize);

                ECB.SetComponent(entity, new Translation { Value = new float3(position.x, position.y, 0) });
                ECB.SetComponent(entity, new Unloadable { Serializable = true });
                ECB.SetComponent(entity, new ChunkData { NewChunk = true, ChunkTick = true, WorldSeed = worldSeed });
                ECB.AddBuffer<TileData>(entity);

                pendingChunks.Remove(chunk);
            }
        }).WithBurst().Schedule();

        //Destroy unloaded entities or select them for serialization
        Entities.WithReadOnly(loadedChunks).ForEach((int entityInQueryIndex, Entity entity, ref Unloadable unloadable, in Translation translation) =>
        {
            int2 chunk = GetChunkFromWorld(new float2(translation.Value.x, translation.Value.y), chunkSize, new float2(0, 0));

            if (!loadedChunks.Contains(chunk))
            {
                if (unloadable.Serializable == true)
                {
                    PECB.AddComponent(entityInQueryIndex, entity, new PendingSave { });
                }
                else
                {
                    PECB.DestroyEntity(entityInQueryIndex, entity);
                }
            }
        }).WithBurst().ScheduleParallel();

        ECBS.AddJobHandleForProducer(Dependency);
        Dependency.Complete();

        //Move selected entities to SaveWorld
        if (Query.IsEmpty == false)
        {
            saveWorld.EntityManager.MoveEntitiesFrom(World.EntityManager, Query);
        }
    }

    protected override void OnDestroy()
    {
        ActiveChunks.Dispose();
        LoadedChunks.Dispose();
        PendingChunks.Dispose();
    }
}

My main code library:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;

public static class WorldUtils
{
    public static int2 GetTileFromWorld(float2 WorldPosition, float2 OriginPosition, float TileSize)
    {
        int2 TilePosition;
        TilePosition.x = (int)math.floor((WorldPosition - OriginPosition).x / TileSize);
        TilePosition.y = (int)math.floor((WorldPosition - OriginPosition).y / TileSize);
        return TilePosition;
    }

    public static float2 GetWorldFromTile(int2 TilePosition, float TileSize, float2 OriginPosition)
    {
        float2 WorldPosition;
        _WorldPosition.x = (TilePosition.x * TileSize) + OriginPosition.x;_
        _WorldPosition.y = (TilePosition.y * TileSize) + OriginPosition.y;_
        return WorldPosition;
    }

    public static float2 GetTileCenter(float2 WorldPosition, float TileSize)
    {
        _return new float2((WorldPosition.x + (TileSize * 0.5f)), (WorldPosition.y + (TileSize * 0.5f)));_
    }

    public static int2 GetChunkFromWorld(float2 WorldPosition, int ChunkSize, float2 OriginPosition)
    {
        int2 ChunkPosition;
        ChunkPosition.x = (int)(math.floor((WorldPosition.x - OriginPosition.x) / ChunkSize));
        ChunkPosition.y = (int)(math.floor((WorldPosition.y - OriginPosition.y) / ChunkSize));
        return ChunkPosition;
    }

    public static float2 GetWorldFromChunk(int2 ChunkPosition, int ChunkSize, float2 OriginPosition)
    {
        float2 WorldPosition;
        _WorldPosition.x = (ChunkPosition.x * ChunkSize) + OriginPosition.x;_
        _WorldPosition.y = (ChunkPosition.y * ChunkSize) + OriginPosition.y;_
        return WorldPosition;
    }

    public static float PerlinSeeder(float WorldSeed)
    {
        float Result = math.cos(WorldSeed);
        return Result;
    }

    public static World FindWorld(string name)
    {
        var worlds = World.All;
        for (int i = 0; i < worlds.Count; i++)
        if (worlds_.Name == name) return worlds*;
        return null;
    }
}

And finally my monobehavior script that tests the other codes:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using static WorldUtils;
using static WorldData;
using static ArchetypeLibrary;

public class Test : MonoBehaviour
{
    public float2 Position;
    EntityManager EntityManager;
    Entity entity;
    
    public float t;
    public bool End;
    public int EndTime;
    public float worldSeed;
    public World worldname;
    
    
    private void Start()
    {
        EntityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        WorldSeed = worldSeed;
        var world = new World("SaveWorld");
    }
    
    private void Update()
    {
        _t += 1 * Time.deltaTime;_
        
        if (Input.GetKeyDown(KeyCode.G))
        {
            t = 0;
            entity = EntityManager.CreateEntity(typeof (Translation), typeof (Loader));
            EntityManager.SetComponentData(entity, new Translation { Value = new float3(Position.x, Position.y, 0) });
            EntityManager.SetComponentData(entity, new Loader { LoadDistance = 40 });
        }
            
        if (End == true && t >= EndTime)
        {
            EntityManager.DestroyEntity(entity);
            t = 0;
        }
    }
}

PS: I just realised that I have no need to post my entire code… lmao

Ummm… answers would be preferable…

ECBS.AddJobHandleForProducer( Dependency );
Dependency.Complete();

Calling Dependency.Complete(); creates pool of commands without executing them yet. So, you’re seeing this error precisely because commands are ready and scheduled for old entities with EndSimulationEntityCommandBufferSystem meanwhile you destroy/move them, before valid buffered commands have any chance of being executed yet, by calling

saveWorld.EntityManager.MoveEntitiesFrom(World.EntityManager, Query);

To fix this, don’t schedule commands with EndSimulationEntityCommandBufferSystem here but just execute them immediately

// ECBS.AddJobHandleForProducer( Dependency );// remove this line
Dependency.Complete();
ECB.Playback( EntityManager );