SystemBase/JOB understanding

Hi

After 1 weeks of struggle, here i’m with 2 things i definitively don’t understand despite watching all unity conference, tutorials on youtube, forums, githubs…

SystemBase Dependency,

From what learned each Entites.foreach.schedule() is meant to works after the completion of the previous schedule(), but from many test i’ve done i never ended to this conclusion, and have various result (both by using schedule and scheduleparallel)

Here is a sample: (for clarity i declare jobHandle manually, i tested whithout and obtain the same results)

Debug.Log("HighlightSelectEnable Enter");
EntityCommandBuffer.ParallelWriter ecb = BeginInit_ECB.CreateCommandBuffer().AsParallelWriter(); // done at the begining
        JobHandle RegimentSelectWhole =
            Entities
                .WithName("Regimentwholeselect")
                .WithBurst()
                .WithAll<RegimentTag, RegimentUnitSelectedTag>()
                .WithNone<RegimentSelectedTag>()
                .ForEach((Entity regimentSelected, int entityInQueryIndex, in DynamicBuffer<Child> unitChild) =>
                {
                    for (int i = 0; i < unitChild.Length; i++)
                    {
                        if (!HasComponent<SelectedUnitTag>(unitChild[i].Value))
                        {
                            ecb.AddComponent<SelectedUnitTag>(entityInQueryIndex, unitChild[i].Value);
                            Debug.Log("HighlightSelectEnable REGIMENTSELECTED SELECT");
                            ecb.AddComponent<UnitNeedHighlightTag>(entityInQueryIndex, unitChild[i].Value);
                            Debug.Log("HighlightSelectEnable REGIMENTSELECTED UNIT NEED HIGHLIGHT");
                        }
                        else
                        {
                            Debug.Log("HighlightSelectEnable false");
                        }
                    }
                    ecb.AddComponent<RegimentSelectedTag>(entityInQueryIndex, regimentSelected);
                    ecb.RemoveComponent<RegimentUnitSelectedTag>(entityInQueryIndex, regimentSelected);
                
                }).Schedule(this.Dependency);
        //RegimentSelectWhole.Complete();
        BeginInit_ECB.AddJobHandleForProducer(this.Dependency);

        Debug.Log("HighlightSelectEnable Enter2");
        EntityQuery querytest = _entityManager.CreateEntityQuery(typeof(UnitNeedHighlightTag));
        Debug.Log(querytest.CalculateEntityCount());
            JobHandle EnableHighlight =
               Entities
                   .WithName("showHighlight")
                   .WithBurst()
                   .WithAll<SelectedUnitTag, UnitNeedHighlightTag>()
                   .WithEntityQueryOptions(EntityQueryOptions.IncludeDisabled)
                   .ForEach((Entity UnitSelected, int entityInQueryIndex, in DynamicBuffer<Child> child) =>
                   {
                       Debug.Log("HighlightSelectEnable UnitSelected");
                       for (int i = 0; i < child.Length; i++)
                       {
                           if (HasComponent<HighlightTag>(child[0].Value))
                           {
                               Debug.Log("HighlightSelectEnable UnitSelected PASS");
                               ecb.RemoveComponent<Disabled>(entityInQueryIndex, child[i].Value);
                           }
                           ecb.RemoveComponent<UnitNeedHighlightTag>(entityInQueryIndex, UnitSelected);
                       }
                }).Schedule(RegimentSelectWhole);
        BeginInit_ECB.AddJobHandleForProducer(EnableHighlight);
            EnableHighlight.Complete();

The console show this:


Despite having the dependency it seems the second «job» is fire first but in the same time it loop through 1 unit implying a selection occure first. (0 is the query between them, not sur it si revelant)

What it was meant to do:

First: select all unit in the regiment by assigning to each entity 2 tags

Second: enable all highlight(child of units)

I know it works it effectively add the tags on each unit on the scene + if i click a second time, it enables the highlights

if i try to force complete the first «job»(RegimentSelectWhole):

The console show this:

To be honest i clearly don’t know how to interpret this result.

I event try to assign a different command buffer (beginInitializationsystem to selection and endInitializationsystem to highlights) and it didn’t work either.

Finally i go around the problem seperating the selectionSystem and and highlightsSystem in different system (highlightsSystem waiting for a query to be <0):

this._test = GetEntityQuery(typeof(UnitNeedHighlightTag)); //if the entity query is empty, the system won’t update

And it works.

But still i really want to know what i learned /understand wrong and why i can’t make it work correctly since i’m sur i will face this issue again in a near futur:

Thanks in advance

JOB VS Entities.foreach?

I read that system base i like a all in one job(both working on copies), but since jobs are still around and commonly used in all github i read when learning ECS, is there specific use case when i should use job instead of entities.foreach? For optimisation or certain action only job can perform?


Yo first execute whats is on the main thread, unless it has dependencies.

Debug.Log("HighlightSelectEnable Enter");
EntityCommandBuffer.ParallelWriter ecb = BeginInit_ECB.CreateCommandBuffer().AsParallelWriter(); // done at the begining
Debug.Log("HighlightSelectEnable Enter2");
EntityQuery querytest = _entityManager.CreateEntityQuery(typeof(UnitNeedHighlightTag));

So in your case, you first execute debug and queries. System is scheduling dependencies of your jobs. Is NOT executing them yet (unless forcing to complete (your second case), or frame is finished).

So you need have that in mind.

Also, because using ecb, ECB does not executes on same frame. Unless forced to complete, otherwise played back.
Hence, even you set tag within first job, results in second job wont be present until next frame (or forced to complete).
So you need have that in mind, there is typically one frame lag, for ECB to be executed.

AH yes my bad actually, i tweaked my code so much i confuse the debugs xD so yeah it actually never enter the second entities.foreach… but why? isn’t the ECB suppose to register all my order and execute them even if it’s in the next frame?

Despite i also tried to use separate commandebuffer (system begin for selection and end for highlights) and the second won’t fire or sometimes if i click fast enough, some will be activated and others won’t like if the system was trying to write while readind the first job.

EDIT ok i understand: it has to wait an entire frame (initialization, simulation, presentation) and only on the next initialization(in my case) the changes made in the ECB will be register

so in my case, separate system is the only option? or is there a way to wait until the next frame?

i try to complete the first job (see above), but it doesn’t seem to fire the next job either

BTW thanks for this precious information about ECB, it really helps for others issues i have x)