My cell entities have 8 neighbor cells stored as entities in an IComponentData struct. When I was counting a cell’s neighbors on the main thread, I was using EntityManager.GetComponentData on the neighbor entities. However, when I jobified he neighbor counting, I haven’t been able to find a reliable way to do the lookup on the neighbor entity into its proper array. As a temp hack, the first entities that I create are the cells (say 10,000, so indices 0-9999), and when I run the neighbor counter system, I create an entity query for my cells and transform the results into a native array of size 10,000, so I can do the lookup. However, when I restart the app and destroy all the entities, the newly created cell entity ids don’t match the same 0-9999 range as before and I get errors, as expected.
I’ve tried chunk iteration, but this didn’t work because the neighbor can be in a different chunk.
I also tried combining component data from chunks in a native array, but that didn’t work either. I tried to reset the World entity count back to 0, but there doesn’t seem to be a way to do this. How can I find the proper array that stored the neighbors?
Speaking of neighbors, instead of storing 8 separate entities in the data struct and doing random array access lookups on these entities in the job, is there a more cache friendly method? The counter system is actually quite fast, but I’m trying to think of different ways to solve this problem.
The render system is my bottleneck. I’m using the standard Rendermesh/Translation/Scale/LocalToWorld setup to perform the rendering. Can I optimize using the Graphics class or some other method?
General ECS Feedback
Before setting the cells’ scales to 0, I was attempting to swap between 2 different shared Rendermesh Components, but couldn’t find a way to do this in a job and it was painfully slow on the main thread
Reloading the scene doesn’t destroy entities or systems. I was surprised but I suppose I shouldn’t have been
The samples and documentation helped a lot
Overall, I like the ECS as it’s a nice, elegant way to separate data from functionality and write really easy to read, performant code. It will be interesting to see how the API evolves over time. For example, I wonder if we’ll always have to manually dispose of our arrays.
There should probably be a sample set up that just demonstrates how you expect people to access outside entities from inside an IJFE, seeing as it’s such a common thing that is not demonstrated in the HelloCube examples.
And TBH you should probably link directly to the samples from the overview page of the ECS manual, since that is by far the most comprehensive and up to date tutorial available right now.
I think a very basic small game sample project could go a long way. There used to be one didn’t there?
At the moment there is cubes been transformed, a cool super optimised but kind of single focussed boid demo and the FPS project which is overwhelming and I’m not sure uses best practices for some DOTS things anyway?
I find it confusing sometimes that some of the docs/info on DOTS is in GitHub docs vs Unity documentation pages.
I use Buffer/ComponentDataFromEntity & [NativeDisableParallelForRestriction] LOTS, however, these are no where to be seen in the samples?
In comparison with some things that are in samples; I haven’t used ForEach, non-job ComponentSystems, anything that converts from GameObjects, Subscenes and I have just one or two uses of IJobChunk. I’m not saying these aren’t useful but might be a good idea to see some heavier use of CDFE & [NDPFR] in some samples?
The type name sounds like a method, at first I also thought it’s a kind of shortcut so I think I “use” it rather than creating an instance of it. (so not keeping the instance) Then when I want to do that in a job, the first thing I thought is that how could I get EntityManager into a job rather than just put that in a job. I was teaching someone months ago and it is weird to say “put ComponentDataFromEntity into a job” because the thing doesn’t sounds like a tangible object but a verb.
Then, without knowing inner of how the job need to know its dependency for read/write, it is not obvious why ceremony to create it from outside and pass to the job is needed. Where other things seems to belongs to the job, like ref args from IJFE (even though it came from system’s entity query, so actually it belongs to the outside) or explicitly put in a job like NativeArray and you feel like you really put something in, putting CDFE in feels like you are trying to add an extension method to a job where it is hiding in an object. Imagine if CDFE could appear as a job field like old style [Inject], even if that is not efficient or magical, it would be more understandable that “the job wants to access this kind of component data from any entity”.
It is also weird that it has “from” in its name but it could be written “to”. Putting [ReadOnly] in front of this type name in a job also give me unintuitive feeling.
"Get"ComponentDataFromEntity() method on EM sounded weird too. It sounds like this method “get component data from [entity]” but it actually “get a new instance of [component data from entity]”. If you interpret it as the former it hides the fact that there is an object that could be put in a job returned.
When I know what I am doing using the indexer to both read and write is nice, but for beginner if the object was named something like ComponentAccessor and is forced to use .Get/.Set it would be more obvious, then maybe when scheduling a job the method to make it would be called "Create"Accessor(/ByEntity)
I wholly agree with this on the naming side. I think the verbosity of ‘ComponentDataFromEntity’ gets in the way for something that has such frequent use and whose purpose is very simple. Also given that you can write to it and it only takes Entity as a parameter, the whole ‘FromEntity’ seems a bit counter-intuitive and redundant.
ComponentAccessor or something short along that vein (though I can’t think of anything better) would make it clearer imho. I’m far from a naming expert though.
I didn’t know the use of ComponentDataFromEntity either until I looked at chunk iteration and some older samples.
Newer samples use GetArchetypeChunkComponentType
In that sense, I guess the samples are too practical. Sometimes I just want to know my options so throw in as many types of ways to get data and comment it for what they can be used and how fast they are in comparison.
What about just ComponentLookup, op does mention wanting to do a lookup and that’s probably how I would’ve gone about phrasing how to get data from a specific entity.
That’s what I initially used to call all my CDFE’s but I think accessor is more succinct, not that I ever thought of that word till 5argon mentioned it. In any event, something other than CDFE I think.
// Implies you want to get component data for an entity from that function call.
GetComponentDataFromEntity<Type>(*entity*)
// implies you're going to get back something with which you can access a component.
GetComponentAccessor<Type>()
Thanks, that solved my problem. For me, the naming and parameters were the confusing part. EntityManager.GetComponentData is clear because it takes an Entity param and returns my specified type of component data. Whereas GetComponentDataFromEntity makes less sense because it doesn’t return a single entity’s data and it doesn’t take an entity argument. The function name is written as though it’s for a single entity but it’s plural. Furthermore, even though it is plural, it’s not returning an array. Instead returns a single struct which I can index (which also isn’t apparent because the overloaded [ ] operator doesn’t show up in visual studio intelisense)
The name “GetComponentDataLookupTable” for the function and ComponentDataLookupTable for the struct would be clearer for me. On the struct, I would have the [ ] overloaded and I would have a function GetComponentData(entity)