Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Klusimo · Nov 07, 2020 at 12:25 PM · dotsnative

DOTS NativeContainers error

Hello there! I have (another :D) a question regarding dots. I have this quite simple script where using jobs and native containers i activate and load chunks based on location, transfer them to one nativelist, then from that one into another, but when i test the .Length of the lists, the first one works fine, but when i change the coordinates at run time, instead of being the same number (adding the new chunks, removing the old) it adds the new ones to the old ones and then lower the total number by 1 every frame. Heres my entire script:


NOTE: In the code I have added if function with two different float2 positions and debug.log with the finalised nativelists for the purposes of testing/debugging. Also i will turn this monobehavior into component system in the fututre, but i am using mono for easier testing.


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

 public class WorldMaster : MonoBehaviour
 {
     public float2 Position;
     public int ChunkSize = 20;
     public int LoadDistance = 40;

     NativeList<int2> ActiveChunks;
     NativeList<int2> LoadedChunks;

     private void Start()
     {
         ActiveChunks = new NativeList<int2>(0, Allocator.Persistent);
         LoadedChunks = new NativeList<int2>(0, Allocator.Persistent);
     }

     private void Update()
     {
         if (Input.GetKeyDown(KeyCode.G))
         {
             Position = new float2(500, 500);
         }else if (Input.GetKeyDown(KeyCode.H))
         {
             Position = new float2(0, 0);
         }

         ActiveChunks.Clear();

         JobHandle activate = ActivateChunks(Position, ChunkSize, LoadDistance, ActiveChunks);
         activate.Complete();

         JobHandle load = LoadChunks(ActiveChunks, LoadedChunks);
         load.Complete();
         Debug.Log(ActiveChunks.Length + " " + LoadedChunks.Length);
     }

     public JobHandle ActivateChunks(float2 Position, int ChunkSize, int LoadDistance, NativeList<int2> ActiveChunks)
     {
         ActivateChunksJob job = new ActivateChunksJob();
         job.Position = Position;
         job.ChunkSize = ChunkSize;
         job.LoadDistance = LoadDistance;
         job.ActiveChunks = ActiveChunks;
         return job.Schedule();
     }

     public JobHandle LoadChunks(NativeList<int2> ActiveChunks, NativeList<int2> LoadedChunks)
     {
         LoadChunksJob job = new LoadChunksJob();
         job.ActiveChunks = ActiveChunks;
         job.LoadedChunks = LoadedChunks;
         return job.Schedule();
     }
 }

 [BurstCompile]
 public struct ActivateChunksJob : IJob
 {
     public float2 Position;
     public int ChunkSize;
     public int LoadDistance;

     int2 chunk;
     public NativeList<int2> ActiveChunks;

     public void Execute()
     {
         for (int x = 0; x < LoadDistance; x++)
         {
             for (int y = 0; y < LoadDistance; y++)
             {
                 chunk = GetChunkFromWorld(Position, ChunkSize, new float2(0, 0)) - LoadDistance / 2 + new int2(x, y);
                 if (!ActiveChunks.Contains(chunk))
                 {
                     ActiveChunks.Add(chunk);
                 }
             }
         }
     }
 }

 [BurstCompile]
 public struct LoadChunksJob : IJob
 {
     public NativeList<int2> ActiveChunks;
     public NativeList<int2> LoadedChunks;

     public void Execute()
     {
         foreach (int2 chunk in ActiveChunks)
         {
             if (!LoadedChunks.Contains(chunk))
             {
                 LoadedChunks.Add(chunk);
             }
         }
         foreach (int2 chunk in LoadedChunks)
         {
             if (!ActiveChunks.Contains(chunk))
             {
                 LoadedChunks.RemoveAt(LoadedChunks.IndexOf(chunk));
             }
         }
     }
 }



I am using my own tiny library of code (thats that using static WorldUtils), from which i am using only one function in this code: GetChunkFromWorld. I am putting the function here as well:


 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;
     }



So, if you would help me debug this code, i would be very happy. Also sorry for spamming the forum. Many thanks :)

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by andrew-lukasik · Nov 08, 2020 at 12:31 AM

Hey, nice job! While I fail to reproduce issue you described I noticed something different:

 foreach( int2 chunk in LoadedChunks )
     if( !ActiveChunks.Contains(chunk) )
         LoadedChunks.RemoveAt( LoadedChunks.IndexOf(chunk) );

This code gives me compiler warning ( entities 0.16.0-preview.21 here). And I suspect, on your machine, this code is not throwing anything (or maybe is? not sure) because it's being auto-magically replaced with standard for loop syntax:

 for( int i=0 ; i<LoadedChunks.Length ; i++ )
 {
     int2 chunk = LoadedChunks[i];
     if( !ActiveChunks.Contains(chunk) )
         LoadedChunks.RemoveAt( LoadedChunks.IndexOf(chunk) );
 }

Which is bad because it obfuscate what's happening here really: some indices are being skipped in the process. Visually producing this pattern:

some cells not unloading immediately

To fix this replace it with for loop that counts indices from last to first:

 for( int i=LoadedChunks.Length-1 ; i!=-1 ; i-- )
 {
     int2 chunk = LoadedChunks[i];
     if( !ActiveChunks.Contains(chunk) )
         LoadedChunks.RemoveAt( LoadedChunks.IndexOf(chunk) );
 }

This is the proper way of removing items from a list while in a loop.


includes code for this mouse-operated debug gizmo:

 using UnityEngine;
 using Unity.Collections;
 using Unity.Mathematics;
 using Unity.Entities;
 using Unity.Jobs;
 
 public class WorldMaster : MonoBehaviour
 {
     [SerializeField] float2 _position;
     [SerializeField] float _chunkSize = 20;
     [SerializeField] int _loadDistance = 40;
     NativeList<int2> _activeChunks;
     NativeList<int2> _loadedChunks;
     JobHandle _dependency;
     void Start ()
     {
         _activeChunks = new NativeList<int2>(0, Allocator.Persistent);
         _loadedChunks = new NativeList<int2>(0, Allocator.Persistent);
     }
     void Update ()
     {
         _dependency.Complete();
         // Debug.Log($"num active:{_activeChunks.Length}, num loaded:{_loadedChunks.Length}");
 
         _dependency = ActivateChunks( _position , _chunkSize , _loadDistance , _activeChunks );
         _dependency = LoadChunks( _activeChunks , _loadedChunks , _dependency );
     }
     void OnDestroy ()
     {
         _activeChunks.Dispose();
         _loadedChunks.Dispose();
     }
     #if UNITY_EDITOR
     void OnDrawGizmos ()
     {
         if( !Application.isPlaying ) return;
 
         _dependency.Complete();
 
         Gizmos.color = new Color{ r=0 , g=1 , b=1 , a=0.3f };
         foreach( int2 i2 in _loadedChunks )
             Gizmos.DrawCube( new Vector3{ x=i2.x*_chunkSize + _chunkSize*0.5f , z=i2.y*_chunkSize + _chunkSize*0.5f } , new Vector3{ x=_chunkSize , z=_chunkSize } );
         
         Gizmos.color = new Color{ r=1 , g=0.92f , b=0.016f , a=0.3f };
         foreach( int2 i2 in _activeChunks )
             Gizmos.DrawWireCube( new Vector3{ x=i2.x*_chunkSize + _chunkSize*0.5f , z=i2.y*_chunkSize + _chunkSize*0.5f } , new Vector3{ x=_chunkSize , z=_chunkSize } );
         
         Gizmos.color = Color.red;
         Gizmos.DrawWireSphere( new Vector3{ x=_position.x , z=_position.y }  , _chunkSize*0.1f );
 
         {
             Ray ray = UnityEditor.HandleUtility.GUIPointToWorldRay( Event.current.mousePosition );
             new Plane( inNormal:Vector3.up , inPoint:Vector3.zero ).Raycast( ray , out float dist );
             float3 hit = ray.origin + ray.direction*dist;
             _position = new float2{ x=hit.x , y=hit.z };
         }
     }
     #endif
     public JobHandle ActivateChunks ( float2 position , float chunkSize , int loadDistance , NativeList<int2> activeChunks , JobHandle dependency = default(JobHandle) )
     {
         ActivateChunksJob job = new ActivateChunksJob();
         job.position = position;
         job.chunkSize = chunkSize;
         job.loadDistance = loadDistance;
         job.activeChunks = activeChunks;
         return job.Schedule( dependency );
     }
     public JobHandle LoadChunks ( NativeList<int2> activeChunks , NativeList<int2> loadedChunks , JobHandle dependency = default(JobHandle) )
     {
         LoadChunksJob job = new LoadChunksJob();
         job.activeChunks = activeChunks;
         job.loadedChunks = loadedChunks;
         return job.Schedule( dependency );
     }
 }
 public struct ActivateChunksJob : IJob
 {
     public float2 position;
     public float chunkSize;
     public int loadDistance;
     public NativeList<int2> activeChunks;
     void IJob.Execute ()
     {
         activeChunks.Clear();
         for( int x=0 ; x<loadDistance ; x++ )
         for( int y=0 ; y<loadDistance ; y++ )
         {
             int2 chunk = GetChunkFromWorld( position , chunkSize ) + new int2{ x = x - loadDistance/2 , y = y - loadDistance/2 };
             if( !activeChunks.Contains(chunk) )
                 activeChunks.Add( chunk );
         }
     }
     int2 GetChunkFromWorld ( float2 worldPosition , float chunkSize )
         => (int2) math.floor( worldPosition/chunkSize );
 }
 public struct LoadChunksJob : IJob
 {
     public NativeList<int2> activeChunks;
     public NativeList<int2> loadedChunks;
     void IJob.Execute ()
     {
         for( int i=0 ; i<activeChunks.Length ; i++ )
         {
             int2 chunk = activeChunks[i];
             if( !loadedChunks.Contains(chunk) )
                 loadedChunks.Add(chunk);
         }
         for( int i=loadedChunks.Length-1 ; i!=-1 ; i-- )
         {
             int2 chunk = loadedChunks[i];
             if( !activeChunks.Contains(chunk) )
                 loadedChunks.RemoveAt( loadedChunks.IndexOf(chunk) );
         }
     }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Klusimo · Nov 08, 2020 at 06:20 PM 0
Share

You solved it! The foreach loop caused it. Now it works fine. $$anonymous$$any thanks! :D

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

212 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to implement custom Native List 1 Answer

DOTS Jobs memory leak and game freezing 1 Answer

Can I store a NativeArray instance by reference? 2 Answers

NativeList Empty Outside Job But Not Inside It 1 Answer

ECS System OnUpdate not being called on Unity 2020.1b7 + UniRx 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges