Search Unity

Native Collection error

Discussion in 'Entity Component System' started by Klusimo, Nov 12, 2020.

  1. Klusimo

    Klusimo

    Joined:
    May 7, 2019
    Posts:
    76
    Hello there, I am working on a code that loads/unloads world around player(the code is bellow). When I start it, I get this error:

    A Native Collection has not been disposed, resulting in a memory leak. Allocated from:
    Unity.Collections.NativeHashSet`1:.ctor(Int32, Allocator) (at Library\PackageCache\com.unity.collections@0.14.0-preview.16\Unity.Collections\NativeHashSet.cs:34)
    WorldMaster:OnCreate() (at Assets\WorldMaster.cs:35)
    Unity.Entities.ComponentSystemBase:CreateInstance(World) (at Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\ComponentSystemBase.cs:123)
    Unity.Entities.World:AddSystem_OnCreate_Internal(ComponentSystemBase) (at Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\World.cs:643)
    Unity.Entities.World:GetOrCreateSystemsAndLogException(IEnumerable`1, Int32) (at Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\World.cs:858)
    Unity.Entities.DefaultWorldInitialization:AddSystemToRootLevelSystemGroupsInternal(World, IEnumerable`1, Int32) (at Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\DefaultWorldInitialization.cs:190)
    Unity.Entities.DefaultWorldInitialization:Initialize(String, Boolean) (at Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities\DefaultWorldInitialization.cs:131)
    Unity.Entities.AutomaticWorldBootstrap:Initialize() (at Library\PackageCache\com.unity.entities@0.16.0-preview.21\Unity.Entities.Hybrid\Injection\AutomaticWorldBootstrap.cs:15)


    And when I create entity with certain component needed for the code(LoaderComponent), it fires another error message:

    InvalidOperationException: The UNKNOWN_OBJECT_TYPE has been deallocated, it is not allowed to access it
    Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <e2bce5d33e704a76a5c9576f4d43769b>:0)
    Unity.Collections.NativeHashMap`2[TKey,TValue].CheckWrite () (at Library/PackageCache/com.unity.collections@0.14.0-preview.16/Unity.Collections/NativeHashMap.cs:541)
    Unity.Collections.NativeHashMap`2[TKey,TValue].Clear () (at Library/PackageCache/com.unity.collections@0.14.0-preview.16/Unity.Collections/NativeHashMap.cs:191)
    Unity.Collections.NativeHashSet`1[T].Clear () (at Library/PackageCache/com.unity.collections@0.14.0-preview.16/Unity.Collections/NativeHashSet.cs:88)
    WorldMaster.OnUpdate () (at Assets/WorldMaster.cs:42)
    Unity.Entities.SystemBase.Update () (at Library/PackageCache/com.unity.entities@0.16.0-preview.21/Unity.Entities/SystemBase.cs:413)
    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)


    I have no idea what the error(s?) is and I tried to debug it for some time. It is in the Generation part of the script definitely, just dont know what. Anyway heres the entire code:

    Note: Even tough I use "chunks" as a way to segment the world, I am not using DOTS chunks in the script so dont worry.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Collections;
    5. using Unity.Mathematics;
    6. using Unity.Transforms;
    7. using Unity.Entities;
    8. using Unity.Jobs;
    9. using Unity.Burst;
    10. using static WorldUtils;
    11.  
    12. public class WorldMaster : SystemBase
    13. {
    14.     int ChunkSize = 20;
    15.  
    16.     EndSimulationEntityCommandBufferSystem ECBS;
    17.  
    18.     EntityArchetype ChunkArchetype;
    19.  
    20.     NativeHashSet<int2> ActiveChunks;
    21.     NativeHashSet<int2> LoadedChunks;
    22.     NativeHashSet<int2> PendingChunks;
    23.  
    24.     protected override void OnCreate()
    25.     {
    26.         ECBS = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    27.  
    28.         ChunkArchetype = EntityManager.CreateArchetype
    29.             (
    30.             typeof(Translation),
    31.             typeof(ChunkData),
    32.             typeof(UnloadTag)
    33.             );
    34.  
    35.         NativeHashSet<int2> ActiveChunks = new NativeHashSet<int2>(0, Allocator.Persistent);
    36.         NativeHashSet<int2> LoadedChunks = new NativeHashSet<int2>(0, Allocator.Persistent);
    37.         NativeHashSet<int2> PendingChunks = new NativeHashSet<int2>(0, Allocator.Persistent);
    38.     }
    39.  
    40.     protected override void OnUpdate()
    41.     {
    42.         ActiveChunks.Clear();
    43.  
    44.         var activeChunks = ActiveChunks;
    45.         var loadedChunks = LoadedChunks;
    46.         var pendingChunks = PendingChunks;
    47.         var chunkSize = ChunkSize;
    48.         var chunkArchetype = ChunkArchetype;
    49.  
    50.         var ECB = ECBS.CreateCommandBuffer();
    51.         var PECB = ECB.AsParallelWriter();
    52.  
    53.         Entities.WithName("Activate_Chunks").ForEach((ref Translation translation, ref Loader loader) =>
    54.         {
    55.             float2 Position = new float2(translation.Value.x, translation.Value.y);
    56.             int LoadDistance = loader.LoadDistance;
    57.  
    58.             for (int x = 0; x < LoadDistance; x++)
    59.             {
    60.                 for (int y = 0; y < LoadDistance; y++)
    61.                 {
    62.                     int2 chunk = GetChunkFromWorld(Position, chunkSize, new float2(0, 0)) - LoadDistance / 2 + new int2(x, y);
    63.                     if (!activeChunks.Contains(chunk))
    64.                     {
    65.                         activeChunks.Add(chunk);
    66.                     }
    67.                 }
    68.             }
    69.         }).WithBurst().Schedule();
    70.  
    71.         Job.WithName("Load_Chunks").WithReadOnly(activeChunks).WithCode(() =>
    72.         {
    73.             var activeChunksArray = activeChunks.ToNativeArray(Allocator.Temp);
    74.  
    75.             for (int i = 0; i < activeChunksArray.Length; i++)
    76.             {
    77.                 int2 chunk = activeChunksArray[i];
    78.                 if (!loadedChunks.Contains(chunk))
    79.                 {
    80.                     loadedChunks.Add(chunk);
    81.                     pendingChunks.Add(chunk);
    82.                 }
    83.             }
    84.             for (int i = activeChunksArray.Length - 1; i != -1; i--)
    85.             {
    86.                 int2 chunk = activeChunksArray[i];
    87.                 if (!activeChunks.Contains(chunk))
    88.                     loadedChunks.Remove(chunk);
    89.             }
    90.         }).WithBurst().Schedule();
    91.  
    92.         Job.WithName("Generate_Chunks").WithCode(() =>
    93.         {
    94.             var pendingChunksArray = pendingChunks.ToNativeArray(Allocator.Temp);
    95.  
    96.             for (int i = pendingChunksArray.Length - 1; i != -1; i--)
    97.             {
    98.                 int2 chunk = pendingChunksArray[i];
    99.  
    100.                 Entity entity = ECB.CreateEntity(chunkArchetype);
    101.                 float2 position = GetWorldFromChunk(chunk, chunkSize, new float2(0,0)) + GetTileCenter(chunk, chunkSize);
    102.                 ECB.SetComponent(entity, new Translation { Value = new float3(position.x, position.y, 0) });
    103.  
    104.                 pendingChunks.Remove(chunk);
    105.             }
    106.         }).WithBurst().Schedule();
    107.     }
    108.  
    109.     protected override void OnDestroy()
    110.     {
    111.         ActiveChunks.Dispose();
    112.         LoadedChunks.Dispose();
    113.         PendingChunks.Dispose();
    114.     }
    115. }
    116.  
    I also have library of my code, from which I used these methods:

    Code (CSharp):
    1. public static float2 GetTileCenter(int2 TilePosition, float TileSize)
    2.     {
    3.         return new float2((TilePosition.x + (TileSize * 0.5f)), (TilePosition.y + (TileSize * 0.5f)));
    4.     }
    5.  
    6.     public static int2 GetChunkFromWorld(float2 WorldPosition, int ChunkSize, float2 OriginPosition)
    7.     {
    8.         int2 ChunkPosition;
    9.         ChunkPosition.x = (int)(math.floor((WorldPosition.x - OriginPosition.x) / ChunkSize));
    10.         ChunkPosition.y = (int)(math.floor((WorldPosition.y - OriginPosition.y) / ChunkSize));
    11.         return ChunkPosition;
    12.     }
    13.  
    14.     public static float2 GetWorldFromChunk(int2 ChunkPosition, int ChunkSize, float2 OriginPosition)
    15.     {
    16.         float2 WorldPosition;
    17.         WorldPosition.x = (ChunkPosition.x * ChunkSize) + OriginPosition.x;
    18.         WorldPosition.y = (ChunkPosition.y * ChunkSize) + OriginPosition.y;
    19.         return WorldPosition;
    20.     }

    And I have testing script to create entity with Loader component to kickstart the whole process:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Mathematics;
    5. using Unity.Transforms;
    6. using UnityEngine;
    7.  
    8. public class Test : MonoBehaviour
    9. {
    10.     public float2 Position;
    11.     EntityManager EntityManager;
    12.  
    13.     private void Start()
    14.     {
    15.         EntityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    16.     }
    17.  
    18.     private void Update()
    19.     {
    20.         if (Input.GetKeyDown(KeyCode.G))
    21.         {
    22.             Entity entity = EntityManager.CreateEntity(typeof (Translation), typeof (Loader));
    23.             EntityManager.SetComponentData(entity, new Translation { Value = new float3(Position.x, Position.y, 0) });
    24.             EntityManager.SetComponentData(entity, new Loader { LoadDistance = 40 });
    25.         }
    26.     }
    27. }
    28.  
    And here is the Loader component (ChunkData and UnloadTag are empty components = tags):

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5.  
    6. public struct Loader : IComponentData
    7. {
    8.     public int LoadDistance;
    9. }
    10.  
     
  2. Klusimo

    Klusimo

    Joined:
    May 7, 2019
    Posts:
    76
    So I fixed it, it was me creating new nativecollections instead of allocating the defined ones.