We are being urged whenever possible to use the new JobComponentSystem and IJobProcessComponentData<> but the big problem I have with this is that of how you build the component query.
I find building component queries to be a lot cleaner, simpler, and more powerful using ComponentGroup. Is there a way to do so while still using this new system?
Perhaps an overload like IJobProcessComponentData ?
Could you possibly show an example of how you would access the component data in the job’s execution? I’ve see how you can pass the group to the job but I don’t see how you actually access it, nor what signature you would use on the IJobProcessComponentData if you are building the component query elsewhere.
I’m writing this on my phone, so I can’t easily construct an example, but in your case, IJobProcessComponentData<MoveVelocity>
, and Execute(ref MoveVelocity moveVelocity) {/*write to move velocity here, or add [Read-only] before "ref"*/};
should be adequate.
Yeah see this is my problem. That is the example the original post gave as well but that isn’t doing what I am talking about. If you are passing the component into the IJobProcesscomponentData signature in the first place, then the usag of the ComponentGroup is ancillary at best.
I want to REPLACE the passing of the component filter in the signature with the ComponentGroup.
For two reasons:
Complex filters in the sigature format are unwieldy and frankly ugly as heck. The ComponentGroup syntax is much cleaner
Component groups can filter by component value and I would like to use that
You can use RequireComponentTag and RequireSubtractiveComponent to filter components without adding it to the functions signature.
For more complex stuff, like filter by shared component value, you should use ComponentGroup.CreateArchetypeChunkArray and pass that to a job or use IJobChunk.
This is the part that I meant when I said it gets ugly and he ComponentGroup syntax is cleaner.
I’m was trying to avoid the manual chunk iteration if possible as it is a lot more code and a lot more confusing then the higher level JobComponentSystem/IJobProcessComponentData
The group is there to ensure you only process MoveVelocities that also have UseGravity. You can use arbitrary filters in the group, the job signature only needs to specify the components you are actually reading/writing (they all need to be declared in the group).
For cases where this is not enough, you can use IJobChunk. Its Execute is called on all the ArchetypeChunks matching your group, and has no need for any generic parameters.
If this is still not enough you can get the chunk array yourself via group.CreateArchetypeChunkArray() and pass it to an IJobParallelFor (I use this only for cases where I need to do an all-to-all operation between two groups).
Whau, didn’t know that: There now is a ScheduleGroup for IJobProcessComponentData jobs allowing you to pass the ComponentGroup instead of getting it created automatically!
I don’t think there is documentation, just replace Schedule with ScheduleGroup/ScheduleGroupSingle passing in your ComponentGroup. You will be responsible for making sure all data requested by your job is actually present.
You still specify the data you actually access using the generic parameters but you can use all the features of ComponentGroup to select the chunks.
I’m still really concerned about the use of generic overloads creeping in all over the place. They are always going to be limiting because you can only work with what there are overloads for. What if I want to work with 10 component streams or 20? You just can’t using the generics, and even if there was an overload for it, the signature would look absurd.
ComponentGroups are a much more elegant way of building a query set of component streams.
The simple reason is: ComponentGroup selects chunks but doesn’t specify what data is accessed. To launch a job you have to specify which data is accessed for dependencies to get resolved correctly.
IJobComponentData does that using it’s type, IJobChunk uses ArchetypeChunkComponentType, ComponentGroup in ComponentSystem just waits on conflicts which isn’t possible from within a job and not performant.
I don’t really see a big problem: IJobChunk isn’t more complex than using a ComponentGroup from ComponentSystem, the only annoying thing is passing the types.
IJobProcessComponentData is as easy as it gets and is great for the small stuff, from which there is a lot in a game.
I believe the reason for the generic job interface signatures is to help Unity schedule jobs in parallel. It must know which data you are actually writing to in a job, to know how to schedule that job. That’s why you must specific a component filter and which components you’ll actually be using in the job.
That’s not to say there couldnt be other ways of telling Unity that information. For example, they could have designed ComponenyGroup such that you specificy what data you’ll be writing to. Not that I’d advising that- just that it would have been possible.
But that’s at least why it is the way it is. I generally want form to follow function, so a syntax that might otherwise seem ugly can seem fine to me, if it’s the smoothest way to accomplish the engineering goal.
So part of my problem here was not thinking about things properly. There are two aspects involved. The selection of entities to operate on based on a component query/filter, and a specification of what component streams are needed for the system to operate as well as the Read/Write permissions of those streams.
ComponentGroup deals with the former, but not the latter.
In the signature for for IJobProcessComponentData, you only need to pass in the component streams you actually want to read or write to, and this is where those permissions are declared.
This is not completely true. When creating a component group the shorthand the actual type the method GetComponentGroup expects is an array of ComponentType, not the C# managed type named Type. There’s an implicit cast from Type to ComponentType that specifies the type as a ReadWrite usage.
It is completely possible to update your example at the top to the following and it should function in the same manner:
I do understand the concern in that the job’s signature can possibly contradict that of what your ComponentGroup is specifying. The thing to keep in mind though is that there’s a lot of boilerplate required to do chunk iteration and it can especially be taxing in the case where most of our systems are likely to only have an execution kernel for a single entity at a time. IJobProcessComponentData is serving as a way of providing a shorthand syntax that removes the need for all the boilerplate around chunk iteration.
If you feel you don’t like using it then don’t, I’d then suggest you stick with chunk iteration, but do know that you’ll likely get a little frustrated with the boilerplate required by it. Personally I try and stick with IJobProcessComponentData, but as soon as I realise that I need a more complex query I’ll switch to chunk iteration completely rather than trying to use a component group to further refine the query.
It’s actually amazing that we get access to the baseline way of working with ECS data. You can build a framework or common code around it to simplify writing common systems that you need for your game.
I suggest you start taking the plunge and study how chunk iteration works. All your complaints about the limitations of IJobProcessComponentData will be gone.