#How to use ComponentLookup in a job?

1 messages · Page 1 of 1 (latest)

olive acorn
#

Have a nice day, guys.

I'd like to ask how to get component of an entity in a job? I instantiated the entity in the job and would like to access its component.

I have tried using BufferLookup but get the error "A component can't have IComponentData and IBufferElementData".
I have tried ComponentLookup:

[BurstCompile]
public void OnUpdate(ref SystemState state)
{
    EntityCommandBuffer.ParallelWriter ecb = 
        GetEntityCommandBuffer(ref state);
    ProcessSpawnerJob spawnerJob = new ()
    {
        ElapsedTime = SystemAPI.Time.ElapsedTime,
        Ecb = ecb,
        CharacterLookup = state.GetComponentLookup<CharacterData>(true)
    };
    
    spawnerJob.ScheduleParallel();
}

And used it in a job

Entity newEntity = Ecb.Instantiate(chunkIndex, spawner.Prefab);
float3 spawnPosition = spawner.SpawnPosition;
spawnPosition.x = i - positionInColumn;

Ecb.SetComponent(chunkIndex, newEntity, 
    LocalTransform.FromPosition(spawnPosition));
Ecb.SetComponent(chunkIndex, newEntity, new CharacterData{
    ID = spawner.ID,
    Destination = new float3
        (i - positionInColumn, 1.0f, int.MaxValue),
    MoveSpeed = CharacterLookup[newEntity].MoveSpeed
});

but get the error "All entities created using EntityCommandBuffer.CreateEntity must be realized via playback()" when using CharacterLookup[newEntity].
I also tried adding ECB.Playback() in the System but get a bunch of other errors too.

Thank you for your time.

fast summit
#

you are using it right, but you are using ECB wrong

#

any entities returned by EntiyCommandBuffer.Instantiate are not real

#

they are just fake entities, made up by ECB to keep track of any commands you pass to it

#

once it gets played back and instantiates entity, that's when it'll get actual entity

#

and it'll redirect all commands used on fake one to real one

#

allthough, need to clarify:
you should use SystemAPI.GetComponentLookup instead

#

SystemState.GetComponentLookup is very slow operation, that should be used in OnCreate only, while SystemAPI codegens it for you

olive acorn
#

Thanks for supporting!
But I still haven't figured out the right way to use ECB.
I updated the OnUpdate like this:

[BurstCompile]
public void OnUpdate(ref SystemState state)
{
    EntityCommandBuffer ecb = 
        GetEntityCommandBuffer(ref state);
    ProcessSpawnerJob spawnerJob = new ()
    {
        ElapsedTime = SystemAPI.Time.ElapsedTime,
        Ecb = ecb.AsParallelWriter(),
        CharacterLookup = SystemAPI.GetComponentLookup<CharacterData>(true)
    };
    
    state.Dependency = spawnerJob.ScheduleParallel(state.Dependency);
    ecb.Playback(state.EntityManager);
}

Like I said before, I hit a bunch of other errors like "A dependency must be assigned..", " You must call JobHandle.Complete()" or even "ECB must be realized via playback()".

fleet gyro
#

Specifically, if you're recording an ECB from a job, you need to make sure that job completes before playing back the ECB. If you're playing back within the same system (as above) then you need state.Dependency.Complete() before ecb.Playback().

olive acorn
#

Sorry for bothering you guys, but I failed to find a way to use ComponentLookup for the entity created within a job. I read the document and understand that ECB is just a record for commands (And I'm using the ECB System so I must not use complete() and playback() manually, as the document indicated). And the ComponentLookup in my understanding that it looks for a component in the real entity.

So, is there any way to make ComponentLookup a command to record? I tried Ecb.AddBuffer but the type ComponentLookup<CharacterData> is not IBufferElementData. If I change ComponentLookup to BufferLookup, I have to add IBufferElementData to CharacterData and get other error that I can't add both IComponentData and IBufferElementData to a same struct.

#

Am I too dumb and stubborn to try this approach? I mean, I can get the character data alright by searching for RefRW/RO in OnUpdate.

fleet gyro
#

So, is there any way to make ComponentLookup a command to record?
No, there's no way to record a lookup through a ComponentLookup into an ECB, or (in general) to record a command to read/Get component values that will be written earlier in the same ECB. This is true even without the presence of temporary/"deferred" entities instantiated by the ECB:

var entA = EntityManager.CreateEntity(typeof(MyComponent));
var entB = EntityManager.CreateEntity(typeof(MyComponent));
// in a job:
ecb.SetComponentData(chunkEntity, entA, new MyComponent(17));
// There's no way to record a command here that uses entA's "new" value for MyComponent
ecb.SetComponentData(chunkIndex, entB, ecb.GetComponentData<MyComponent>(entA)); // nope!
ecb.SetComponentData(chunkIndex, entB, MyComponentLookup[entA]); // nope!
#

But while you can't record a deferred lookup on an entity's value that was assigned by an ECB, in many cases you have direct access to the value you've just assigned. To continue the above example, ecb.SetComponentData(chunkIndex, entB, new MyComponent(17)); // yes!

#

So, looking back at your original example: What exactly is the MoveSpeed field you're looking up? Is that data you could read from GetComponentData<MoveSpeed>(spawner.Prefab) instead of from the freshly-created prefab instance (which presumably has the same default move speed as the prefab itself)? Or something you could compute based on other data stored on the prefab entity?

olive acorn
#

I have a CharacterData component which is attached to a entity prefab with these properties:

public struct CharacterData: IComponentData
 public int ID { get; set; }
 public float3 Direction { get; set; }
 public float MoveSpeed { get; set; }

I'd like the spawner to control its ID and Direction on instantiating, but not the preconfigured MoveSpeed which is set directly in the prefab and can change by other System, just not the Spawner one. (I put the MoveSpeed to fetch the ComponentLookup in the example just for testing). If I use SetComponentData, the value that set in the prefab will be lost.

I know there are many ways to achieve the goal including adjusting/dividing CharacterData to more suitable components or updating the component in Spawner System's OnUpdate, etc.
I'm just trying new things.

If the answer to the question using ComponentLookup for an instantiated entity within a job is impossible. The topic is pretty resolved.

Thank you all for your time and supports!

gloomy saddle
#

If I use SetComponentData, the value that set in the prefab will be lost.
you can read the MoveSpeed off the prefab

#
var characterData = CharacterDatas[Prefab];
var instance = ecb.Instantiate(Prefab);
characterData.ID = 1234;
characterData.Direction = float.Up():
ecb.SetComponentData(instance, characterData);```