Chunk component data
Use chunk components to associate data with a specific chunk.
Chunk components contain data that applies to all entities in a specific chunk. For example, if you had chunks of entities representing 3D objects that are organized by proximity, you could store a collective bounding box for the entities in a chunk using a chunk component. Chunk components use the interface type IComponentData.
Add and set the values of a chunk component using Although chunk components can have values unique to an individual chunk, they are still part of the archetype of the entities in the chunk. Thus if you remove a chunk component from an entity, that entity is moved to a different chunk (possibly a new one). Likewise, if you add a chunk component to an entity, that entity moves to a different chunk since its archetype changes; the addition of the chunk component does not affect the remaining entities in the original chunk.
If you change the value of a chunk component using an entity in that chunk, it changes the value of the chunk component common to all the entities in that chunk. If you change the archetype of an entity such that it moves into a new chunk that happens to have the same type of chunk component, then the existing value in the destination chunk is unaffected. (If the entity is moved to a newly created chunk, then a new chunk component for that chunk is also created and assigned its default value.)
The main differences between working with chunk components and general-purpose components is that you use different functions to add, set, and remove them. Chunk components also have their own ComponentType functions for use in defining entity archetypes and queries.
Relevant APIs
Declaring a chunk component
Chunk components use the interface type IComponentData.
public struct ChunkComponentA : IComponentData
{
public float Value;
}
Creating a chunk component
You can add a chunk component directly, using an entity in the target chunk or using an entity query that selects a group of target chunks. Chunk components cannot be added inside a Job, nor can they be added with an EntityCommandBuffer.
You can also include chunk components as part of the EntityArchetype or list of ComponentType objects used to create entities and the chunk components are created for each chunk storing entities with that archetype. Use ComponentType.ChunkComponent<T> or ComponentType.ChunkComponentReadOnly<T> with these methods. Otherwise, the component is treated as a general-purpose component instead of a chunk component.
With an entity in a chunk
Given an entity in the target chunk, you can add a chunk component to the chunk using the EntityManager.AddChunkComponentData<T>() function:
EntityManager.AddChunkComponentData<ChunkComponentA>(entity);
Using this method, you cannot immediately set a value for the chunk component.
With an EntityQuery
Given an entity query that selects all the chunks to which you want to add a chunk component, you can add and set the component using the EntityManager.AddChunkComponentData<T>() function:
EntityQueryDesc ChunksWithoutComponentADesc = new EntityQueryDesc()
{
None = new ComponentType[] {ComponentType.ChunkComponent<ChunkComponentA>()}
};
ChunksWithoutChunkComponentA = GetEntityQuery(ChunksWithoutComponentADesc);
EntityManager.AddChunkComponentData<ChunkComponentA>(ChunksWithoutChunkComponentA,
new ChunkComponentA() {Value = 4});
Using this method, you can set the same initial value for all the new chunk components.
With an EntityArchetype
When creating entities with an archetype or list of component types, include the chunk component types in the archetype:
ArchetypeWithChunkComponent = EntityManager.CreateArchetype(
ComponentType.ChunkComponent(typeof(ChunkComponentA)),
ComponentType.ReadWrite<GeneralPurposeComponentA>());
var entity = EntityManager.CreateEntity(ArchetypeWithChunkComponent);
or list of component types:
ComponentType[] compTypes = {ComponentType.ChunkComponent<ChunkComponentA>(),
ComponentType.ReadOnly<GeneralPurposeComponentA>()};
var entity = EntityManager.CreateEntity(compTypes);
Using these methods, the chunk components for new chunks created as part of entity construction receive the default struct value. Chunk components in existing chunks are not changed. See Updating a chunk component for how to set the chunk component value given a reference to an entity.
Reading a chunk component
You can read a chunk component using the ArchetypeChunk object representing the chunk or using an entity in the target chunk.
With the ArchetypeChunk instance
Given a chunk, you can read its chunk component using the EntityManager.GetChunkComponentData<T> function. The following code iterates over all the chunks matching a query and accesses a chunk component of type ChunkComponentA:
var chunks = ChunksWithChunkComponentA.CreateArchetypeChunkArray(Allocator.TempJob);
foreach (var chunk in chunks)
{
var compValue = EntityManager.GetChunkComponentData<ChunkComponentA>(chunk);
//..
}
chunks.Dispose();
With an entity in a chunk
Given an entity, you can access a chunk component in the chunk containing that entity with EntityManager.GetChunkComponentData<T>:
if(EntityManager.HasChunkComponent<ChunkComponentA>(entity))
chunkComponentValue = EntityManager.GetChunkComponentData<ChunkComponentA>(entity);
You can also set up a fluent query to select only entities that have a chunk component:
Entities.WithAll(ComponentType.ChunkComponent<ChunkComponentA>()).ForEach(
(Entity entity) =>
{
var compValue = EntityManager.GetChunkComponentData<ChunkComponentA>(entity);
//...
});
Note that you cannot pass a chunk component to the for-each portion of the query. Instead, you must pass the Entity object and use the EntityManager to access the chunk component.
Updating a chunk component
You can update a chunk component given a reference to the chunk it belongs to. In an IJobChunk Job, you can call ArchetypeChunk.SetChunkComponentData. On the main thread, you can use the EntityManager version, EntityManager.SetChunkComponentData. Note that you cannot access chunk components in an IJobForEach Job because you do not have access to the ArchetypeChunk object or the EntityManager.
With the ArchetypeChunk instance
To update a chunk component in a Job, see Reading and writing in a JobComponentSystem.
To update a chunk component on the main thread, use the EntityManager:
EntityManager.SetChunkComponentData<ChunkComponentA>(chunk,
new ChunkComponentA(){Value = 7});
With an Entity instance
If you have an entity in the chunk rather than the chunk reference itself, you can also use the EntityManger to get the chunk containing the entity:
var entityChunk = EntityManager.GetChunk(entity);
EntityManager.SetChunkComponentData<ChunkComponentA>(entityChunk,
new ChunkComponentA(){Value = 8});
Detecting changes in data
Use component change versions to detect when a chunk component needs to be updated for a given chunk. ECS updates the component versions for a chunk whenever the data in a component is accessed as writable or when an entity is added or removed from the chunk.
For example, if the chunk component contains the center point of the entities in a chunk, calculated from the LocalToWorld component of those entities, you can check the version of the LocalToWorld components to determine whether the chunk component should be updated. If your chunk component is derived from more than one component, you should check the versions of all of the components to see if any of them changed.
See Skipping chunks with unchanged entities for additional information.
Reading and writing in a JobComponentSystem
In an IJobChunk inside a JobComponentSystem, you can access chunk components using the chunk parameter passed to the IJobChunk Execute function. As with any component data in an IJobChunk Job, you must pass a ArchetypeChunkComponentType<T> object to the Job using a field struct in order to access the component.
The following system defines a query that selects all entities and chunks with a chunk component of type, ChunkComponentA. It then runs an IJobChunk Job using the query to iterate over the selected chunks and access the individual chunk components. The Job uses the ArchetypeChunk GetChunkComponentData and SetChunkComponentData functions to read and write the chunk component data.
using Unity.Burst;
using Unity.Entities;
using Unity.Jobs;
public class ChunkComponentChecker : JobComponentSystem
{
private EntityQuery ChunksWithChunkComponentA;
protected override void OnCreate()
{
EntityQueryDesc ChunksWithComponentADesc = new EntityQueryDesc()
{
All = new ComponentType[]{ComponentType.ChunkComponent<ChunkComponentA>()}
};
ChunksWithChunkComponentA = GetEntityQuery(ChunksWithComponentADesc);
}
[BurstCompile]
struct ChunkComponentCheckerJob : IJobChunk
{
public ArchetypeChunkComponentType<ChunkComponentA> ChunkComponentATypeInfo;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
{
var compValue = chunk.GetChunkComponentData(ChunkComponentATypeInfo);
//...
var squared = compValue.Value * compValue.Value;
chunk.SetChunkComponentData(ChunkComponentATypeInfo,
new ChunkComponentA(){Value= squared});
}
}
protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
var job = new ChunkComponentCheckerJob()
{
ChunkComponentATypeInfo = GetArchetypeChunkComponentType<ChunkComponentA>()
};
return job.Schedule(ChunksWithChunkComponentA, inputDependencies);
}
}
Note that if you are only reading a chunk component and not writing, you should use ComponentType.ChunkComponentReadOnly when defining your entity query to avoid creating unnecessary Job scheduling constraints.
Deleting a chunk component
Use the EntityManager.RemoveChunkComponent functions to delete a chunk component. You can remove a chunk component given an entity in the target chunk or you can remove all the chunk components of a given type from all chunks selected by an entity query. If you remove a chunk component from an individual entity, that entity moves to a different chunk because the archetype of the entity changes; the chunk itself retains the unchanged chunk component as long as there are other entities remaining in the chunk.
Using a chunk component in a query
To use a chunk component in an entity query, you must specify the type using either the ComponentType.ChunkComponent<T> or ComponentType.ChunkComponentReadOnly<T> functions. Otherwise, the component is treated as a general-purpose component instead of a chunk component.
In an EntityQueryDesc
The following query description can be used to create an entity query that selects all chunks -- and entities in those chunks -- that have a chunk component of type, ChunkComponentA:
EntityQueryDesc ChunksWithChunkComponentADesc = new EntityQueryDesc()
{
All = new ComponentType[]{ComponentType.ChunkComponent<ChunkComponentA>()}
};
In an EntityQueryBuilder lambda function
The following fluent query iterates over all entities in chunks that have a chunk component of type, ChunkComponentA:
Entities.WithAll(ComponentType.ChunkComponentReadOnly<ChunkCompA>())
.ForEach((Entity ent) =>
{
var chunkComponentA = EntityManager.GetChunkComponentData<ChunkCompA>(ent);
});
Note: you cannot pass a chunk component to the lambda function itself. To read or write the value of a chunk component in a fluent query, use the ComponentSystem.EntityManager property. Modifying a chunk component effectively modifies the value for all entities in the same chunk; it does not move the current entity to a different chunk.