Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How to use IEnableableComponent with IJobEntity

Discussion in 'Entity Component System' started by joshrs926, Jun 22, 2023.

  1. joshrs926

    joshrs926

    Joined:
    Jan 31, 2021
    Posts:
    105
    How do I write an IJobEntity that can enable and disable IEnableableComponents? I know you can use an ECB, EntityManager, or ComponentLookup, but I'm wondering if there's a straightforward way like there is with idiomatic foreach. In foreach you can use EnabledRefRW<> to be able to directly set the enabled state. But from my understanding, idiomatic foreach is single threaded. Is there anything like that for IJobEntity?
     
  2. Wobbers

    Wobbers

    Joined:
    Dec 31, 2017
    Posts:
    55
    EnabledRefRW works in jobs as well.
    Code (CSharp):
    1. public partial struct WeaponResetTriggerJob : IJobEntity
    2. {
    3.     public void Execute(EnabledRefRW<WeaponTrigger> trigger)
    4.     {
    5.         trigger.ValueRW = false;
    6.     }
    7. }
    You can add WithOptions attribute
    [WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)]
    when needed
     
    joshrs926 likes this.
  3. joshrs926

    joshrs926

    Joined:
    Jan 31, 2021
    Posts:
    105
    Oh that’s great know thanks!
     
  4. joshrs926

    joshrs926

    Joined:
    Jan 31, 2021
    Posts:
    105
    Well it looks like I can use EnabledRefRW<> in an IJobEntity's Execute method, but I can't also use the component by itself at the same time. I would want to do so so I could access its "value" field. The following gives me compiler errors.
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Entities;
    3.  
    4. [BurstCompile]
    5. public partial struct MySystem : ISystem
    6. {
    7.     [BurstCompile]
    8.     public void OnUpdate(ref SystemState state)
    9.     {
    10.         new Job().ScheduleParallel();
    11.     }
    12.  
    13.     [BurstCompile]
    14.     partial struct Job : IJobEntity
    15.     {
    16.  
    17.         [BurstCompile]
    18.         public void Execute(
    19.             ref MyComponent myComponent,
    20.             EnabledRefRW<MyComponent> enabledMyComponent)
    21.         {
    22.            
    23.         }
    24.     }
    25. }
    26.  
    27. public struct MyComponent : IComponentData, IEnableableComponent
    28. {
    29.     public float value;
    30. }
    Here's the 2 compiler errors I get:

    - Packages\PhysicsCharacterController\Runtime\Systems\TestSystem.cs(20,39): error SGJE0017: global::MySystem.Job has duplicate components of same type MyComponent. Remove all but one to fix.

    - Packages\PhysicsCharacterController\Runtime\Systems\TestSystem.cs(37,37): error CS0426: The type name 'InternalCompilerQueryAndHandleData' does not exist in the type 'MySystem.Job'
     
  5. Wobbers

    Wobbers

    Joined:
    Dec 31, 2017
    Posts:
    55
    I am doing that within a foreach and it works without problems (Entities 1.0.11):
    Code (CSharp):
    1.         foreach (var (damageFlag, tickDamage, e) in
    2.                  SystemAPI.Query<EnabledRefRW<TickDamage>, RefRW<TickDamage>>()
    3.                           .WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)
    4.                           .WithEntityAccess())
    5.         {
    6.             tickDamage.ValueRW.Cooldown -= SystemAPI.Time.DeltaTime;
    7.             damageFlag.ValueRW = tickDamage.ValueRW.Cooldown <= 0;
    8.             if (damageFlag.ValueRW)
    9.                 tickDamage.ValueRW.Cooldown += tickDamage.ValueRW.Interval;
    10.         }
    Weird if it works in foreach but not in IJobEntity. Maybe a bug? Maybe
    IgnoreComponentEnabledState
    is required in this case?
     
  6. FaithlessOne

    FaithlessOne

    Joined:
    Jun 19, 2017
    Posts:
    257
  7. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,266
    Really? Even with the attribute, I'm still prevented from querying both the component data ref and its enabled ref in an IJE (1.0.11), and have to use a lookup instead.
    Code (CSharp):
    1. public partial struct ModifyDataAndEnableable : ISystem {
    2.  
    3.     [BurstCompile] public void OnUpdate( ref SystemState state ) {
    4.         new ModifyDataAndEnableableJob().ScheduleParallel();
    5.     }
    6.  
    7.     [WithOptions( EntityQueryOptions.IgnoreComponentEnabledState )]
    8.     [BurstCompile] partial struct ModifyDataAndEnableableJob : IJobEntity {
    9.         void Execute( EnabledRefRW<TestEnableableData> testEnableableState, ref TestEnableableData testEnableableData ) {
    10.          
    11.         }
    12.     }
    13. }
    14.  
    15. public struct TestEnableableData : IComponentData, IEnableableComponent {
    16.     public float someData;
    17. }
     
  8. FaithlessOne

    FaithlessOne

    Joined:
    Jun 19, 2017
    Posts:
    257
    Oh, sorry some misunderstanding here. You are right, you have to use a lookup. I also experienced this restriction. The attribute WithOptions(EntityQueryOptions.IgnoreComponentEnabledState) only helps to query disabled EnableableComponents on a job.
     
    Marble likes this.
  9. joshrs926

    joshrs926

    Joined:
    Jan 31, 2021
    Posts:
    105
    @cort_of_unity I've seen you answering questions about the Entities package. I hope you don't mind me pinging you here. Could you comment on this? Is there a way to both read/write a components enabled flag and that same components fields by having it as a parameter in the Execute method of an IJobEntity?
     
  10. ThomasEgan

    ThomasEgan

    Joined:
    Dec 17, 2013
    Posts:
    20
    What you can do as a workaround is create an aspect with EnabledRefRW and RefRW of the same component type.
    If you use this be aware that you won't be able to use the WithDisabledAttribute on an IJobEntity (codegen bug?) so as a workaround for this just use an EntityQuery when scheduling the job
     
    Marble likes this.