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 jankrib · Jan 17, 2021 at 08:07 PM · dotssystems

Issue with DestroyEntity in ECS

I'm trying to make a system in ECS, that will show an outline around objects. My plan is to show this with two additional materials (mask and fill) for an entity. My starting point is the asset "Quick Outline"

As far as I have understood I have to make new entities to show additional materials for an entity so the way I have implemented it is to have a component like this:

 public struct OutlineComponent : IComponentData
 { 
     public Entity MaskEntity;
     public Entity FillEntity;
     public bool Show;
 }



Then I have a system where I do this in OnUpdate:

 var ecb = this.ecbSystem.CreateCommandBuffer();
 Entities
 .WithoutBurst()
 .ForEach((Entity entity, int entityInQueryIndex, ref OutlineComponent outline, in RenderMesh renderMesh, in RenderBounds renderBounds) =>
 {

     if (outline.Show && outline.FillEntity == Entity.Null)
     {
         outline.FillEntity = CreateChildEntity(entity, renderMesh, archetype, materialFill, ref ecb);
     }
     else if (!outline.Show && outline.FillEntity != Entity.Null)
     {
         ecb.DestroyEntity(outline.FillEntity);
         outline.FillEntity = Entity.Null;
     }

     if (outline.Show && outline.MaskEntity == Entity.Null)
     {
         outline.MaskEntity = CreateChildEntity(entity, renderMesh, archetype, materialMask, ref ecb);
     }
     else if (!outline.Show && outline.MaskEntity != Entity.Null)
     {
         ecb.DestroyEntity(outline.MaskEntity);
         outline.MaskEntity = Entity.Null;
     }
 }).Run();

Where this.ecbSystem is EndSimulationEntityCommandBufferSystem CreateChildEntity(...) calls ecb.CreateEntity() and adds components


Flipping the OutlineComponent.Show bool to true works and the outline is displayed, but when set to false I get this error:

 ArgumentException: System.InvalidOperationException: playbackState.CreateEntityBatch passed to SelectEntity is null

Anyone who can help me to solve this issue?

Would also welcome all feedback on the approach in general, since I'm new to ECS.


EDIT Everything works if I use EntityQuery, a normal foreach loop and the EntityManager directly instead of the command buffer.

Comment
Add comment · Show 3
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 andrew-lukasik · Jan 17, 2021 at 09:31 PM 0
Share
 if( thatEntity!=Entity.Null ) ecb.DestroyEntity( thatEntity );
 else Debug("oh noes, that entity is totally null! O:");

?

avatar image jankrib andrew-lukasik · Jan 18, 2021 at 05:49 AM 0
Share

Thank you for the reply, but I'm not sure I understand what you mean. outline.FillEntity and outline.$$anonymous$$askEntityis by design null when outline.Show is false. The idea here is that when Show is flipped to false, they will not be null and therefore destroyed and at least we know that the DestroyEntity method is called since it is producing the error.

avatar image andrew-lukasik jankrib · Jan 18, 2021 at 10:08 AM 0
Share

Oh sorry, I somehow didn't noticed you was testing for that already

1 Reply

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

Answer by andrew-lukasik · Jan 18, 2021 at 11:04 AM

EDIT: (Long story short) Entity e = ecb.CreateEntity() returns a reference to deferred entity which won't be automagically recognized outside scope of a single job run. Here is a solution to make ECB fix (remap) those deferred Entity field references:

 compData.entity = ecb.CreateEntity( archetype );
 ecb.SetComponent( entity , compData );

Theory put to test:


 using Debug = UnityEngine.Debug;
 using Unity.Entities;
 using Unity.Rendering;
 
 public class IssuewithDestroyEntityInECS : SystemBase
 {
     EndSimulationEntityCommandBufferSystem ecbSystem;
     EntityArchetype archetype;
 
     protected override void OnCreate ()
     {
         ecbSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
         archetype = EntityManager.CreateArchetype(
             typeof(OutlineComponent) ,
             typeof(RenderMesh) ,
             typeof(RenderBounds)
         );
 
         var ENTITY_1 = EntityManager.CreateEntity( archetype );
         EntityManager.SetComponentData( ENTITY_1 , new OutlineComponent{
             Show = true ,
             MaskEntity = Entity.Null ,
             FillEntity = Entity.Null ,
         } );
         EntityManager.SetName( ENTITY_1 , nameof(ENTITY_1) );
 
         var ENTITY_2 = EntityManager.CreateEntity( archetype );
         EntityManager.SetComponentData( ENTITY_2 , new OutlineComponent{
             Show = false ,
             MaskEntity = Entity.Null ,
             FillEntity = EntityManager.CreateEntity() ,
         } );
         EntityManager.SetName( ENTITY_2 , nameof(ENTITY_2) );
 
         var ENTITY_3 = EntityManager.CreateEntity( archetype );
         EntityManager.SetComponentData( ENTITY_3 , new OutlineComponent{
             Show = false ,
             MaskEntity = EntityManager.CreateEntity() ,
             FillEntity = Entity.Null ,
         } );
         EntityManager.SetName( ENTITY_3 , nameof(ENTITY_3) );
     }
     
     protected override void OnUpdate ()
     {
         var ecb = this.ecbSystem.CreateCommandBuffer();
         var entityManager = EntityManager;
 
         Entities
             .WithChangeFilter<OutlineComponent>()
             .ForEach( ( Entity entity , in OutlineComponent IN_outline ) =>
             {
                 OutlineComponent outline = IN_outline;
                 bool isDirty = false;
 
                 // TEST: force to switch every frame
                 outline.Show = !outline.Show; isDirty = true;
 
                 if( outline.Show && outline.FillEntity==Entity.Null )
                 {
                     outline.FillEntity = ecb.CreateEntity();
                     isDirty = true;
                 }
                 else if( !outline.Show && outline.FillEntity!=Entity.Null )
                 {
                     ecb.DestroyEntity( outline.FillEntity );
                     outline.FillEntity = Entity.Null;
                     isDirty = true;
                 }
 
                 if( outline.Show && outline.MaskEntity==Entity.Null )
                 {
                     outline.MaskEntity = ecb.CreateEntity();
                     isDirty = true;
                 }
                 else if( !outline.Show && outline.MaskEntity!=Entity.Null )
                 {
                     ecb.DestroyEntity( outline.MaskEntity );
                     outline.MaskEntity = Entity.Null;
                     isDirty = true;
                 }
 
                 if( isDirty )
                     ecb.SetComponent( entity , outline );
             })
             .WithoutBurst().Run();
 
         ecbSystem.AddJobHandleForProducer( this.Dependency );
     }
 }
 
 public struct OutlineComponent : IComponentData
 {
     public Entity MaskEntity;
     public Entity FillEntity;
     public bool Show;
 }

Unity 2020.2.1f1

Entities 0.16.0-preview.21


Comment
Add comment · Show 7 · 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 jankrib · Jan 19, 2021 at 06:24 AM 0
Share

I did not get any errors running your code, but I did if I tried to switch the Show On/Off during runtime.

I used this in a $$anonymous$$onoBehaviour.LateUpdate

 if(UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.O))
 {
     var query = entity$$anonymous$$anager.CreateEntityQuery(typeof(OutlineComponent));

     using(var entities = query.ToEntityArray(Unity.Collections.Allocator.Temp))
     {
         foreach(var entity in entities)
         {
             var outline = entity$$anonymous$$anager.GetComponentData<OutlineComponent>(entity);
             outline.Show = !outline.Show;
             UnityEngine.Debug.Log($"Toggle outline to {outline.Show} for {entity$$anonymous$$anager.GetName(entity)}");
             entity$$anonymous$$anager.SetComponentData<OutlineComponent>(entity, outline);
         }
     }
 }
avatar image andrew-lukasik jankrib · Jan 19, 2021 at 07:28 AM 0
Share

Working around dependency graph (JobHandles) like this will cause such errors. Especially when command buffer is involved, sooner or later, it creates race conditions.

You need to introduce dependency back into this workflow to fix the issue ie.: to stop modifying chunks after commands were created but not executed yet.

avatar image jankrib andrew-lukasik · Jan 19, 2021 at 03:11 PM 0
Share

Thank you for helping me. It makes sense. One more test. I tried to add outline.Show = !outline.Show; to the beginning of the ForEach (right before the first if statement). At least then there are no dependency issues was my thinking, but it fails immediately with: ArgumentException: Invalid Entity version Do you understand what is going on here?

Show more comments

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

113 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

Related Questions

ECS NativeHashMap GetKeyArray throws IndexOutOfRangeException 0 Answers

Npc traffic (Pedestrian) system 0 Answers

ECS How can I pass a variable into rendermesh closure? 0 Answers

How to use multiple DynamicBuffer in one entity 1 Answer

[ECS] How to dynamically update body friction 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