SystemAPI overview
SystemAPI is a class that provides caching and utility methods for accessing data in an entity's world. It works in non-static methods in SystemBase and non-static methods in ISystem that take ref SystemState
as a parameter.
You can use it to perform the following actions:
- Iterate through data: Retrieve data per entity that matches a query.
- Query building: Get a cached EntityQuery, which you can use to schedule jobs, or retrieve information about that query.
- Access data: Get component data, buffers, and EntityStorageInfo.
- Access singletons: Find single instances of data, also known as singletons.
All SystemAPI
methods directly map to the system you put them in. This means a call like SystemAPI.GetSingleton<T>()
checks whether the world that's contained on the system can perform the action.
SystemAPI
uses stub methods, which mean that they all directly call ThrowCodeGenException
. This is because SystemAPI
uses Roslyn source generators which replaces the methods with the correct lookup. This means that you can't call SystemAPI
outside a supported context.
To inspect your systems, use an IDE that supports source generation, such as Visual Studio 2022+ or Rider 2021.3.3+. You can then select Go To Definition to inspect the generated code on the system you're using SystemAPI within. This illustrates why you need to mark systems as partial
.
Iterate through data
To iterate through a collection of data on the main thread, you can use the Query method in both ISystem and SystemBase system types. It uses C#’s idiomatic foreach
syntax. For more information, see the documentation on SystemAPI.Query overview
Query building
The QueryBuilder method gets an EntityQuery
, which you can then use to schedule jobs or retrieve information about the query. It follows the same syntax as EntityQueryBuilder.
The benefit of using SystemAPI.QueryBuilder
is that the method caches the data. The following example shows how the SystemAPI
call is fully compiled:
/// SystemAPI call
SystemAPI.QueryBuilder().WithAll<HealthData>().Build();
/// ECS compiles it like so:
EntityQuery query;
public void OnCreate(ref SystemState state){
query = new EntityQueryBuilder(state.WorldUpdateAllocator).WithAll<HealthData>().Build(ref state);
}
public void OnUpdate(ref SystemState state){
query;
}
Access data
SystemAPI
contains the following utility methods that you can use to access data in a system's world:
These SystemAPI
methods cache in your systems' OnCreate
and call .Update
before any call. Also, when you call these methods, ECS makes sure that the calls are synced before they get lookup access. This means that a call like SystemAPI.SetBuffer<MyElement>
, which uses a lookup, in this case BufferLookup<MyElement>
, causes all jobs that are currently writing to MyElement
to complete. Calls such as GetEntityTypeHandle
and GetBufferLookup
don't cause syncs.
This is a useful way to pass data like IJobEntity
and IJobChunk
into jobs without causing a sync on the main thread. For example:
new MyJob{healthLookup=SystemAPI.GetComponentLookup<HealthData>(isReadOnly:true)};
Because ECS caches this data, you can directly call it in OnUpdate
. You don't need to write the whole thing, because it's equal to:
ComponentLookup<HealthData> lookup_HealthData_RO;
public void OnCreate(ref SystemState state){
lookup_HealthData_RO = state.GetComponentLookup<HealthData>(isReadOnly:true);
}
public void OnUpdate(ref SystemState state){
lookup_HealthData_RO.Update(ref state);
new MyJob{healthLookup=lookup_HealthData_RO};
}
Entities.ForEach compatibility
Only a selection of SystemAPI methods work in Entities.ForEach. These are as follows:
Data type | API |
---|---|
Component data | GetComponentLookup GetComponent SetComponent HasComponent |
Buffers | GetBufferLookup GetBuffer HasBuffer |
EntityInfo | GetEntityStorageInfoLookup Exists |
Aspects | GetAspect |
Access singletons
SystemAPI
has singleton methods that check to make sure that there is only a single instance of the data it retrieves when invoked. These methods don't sync, which gives them a performance boost.
For example, a call like SystemAPI.GetSingleton<MyComponent>()
queries whether there is only one entity that matches the given criteria, and if so, gets the component MyComponent
. It does this without asking the job system to complete all jobs that use MyComponent
.
This is a useful alternative to EntityManager.GetComponentData, which syncs data. For example, when you call EntityManager.GetComponentData<MyComponent>
, all jobs that write to MyComponent
complete.
The following are a list of methods that you can use to access singleton data in SystemAPI
:
Data type | API name |
---|---|
Singleton component data | GetSingleton TryGetSingleton GetSingletonRW TryGetSingletonRW SetSingleton |
Singleton entity data | GetSingletonEntity TryGetSingletonEntity |
Singleton buffers | GetSingletonBuffer TryGetSingletonBuffer |
All singletons | HasSingleton |
Managed versions of SystemAPI
The SystemAPI.ManagedAPI
namespace exposes managed versions of the methods in SystemAPI, which you can use to access managed components.
Data type | API name |
---|---|
Component data | ManagedAPI.GetComponent ManagedAPI.HasComponent ManagedAPI.IsComponentEnabled ManagedAPI.SetComponentEnabled |
Handles | ManagedAPI.GetSharedComponentTypeHandle |
It also contains the following managed versions of the singleton APIs:
Data type | API name |
---|---|
Singleton component data | ManagedAPI.GetSingleton ManagedAPI.TryGetSingleton |
Singleton entity data | ManagedAPI.GetSingletonEntity ManagedAPI.TryGetSingletonEntity |
All singletons | ManagedAPI.HasSingleton |
You can also use the ManagedAPI.UnityEngineComponent method, which extends SystemAPI.Query so you can query over MonoBehaviours, scriptable objects, and UnityEngine components like UnityEngine.Transform
. For example:
foreach (var transformRef in SystemAPI.Query<SystemAPI.ManagedAPI.UnityEngineComponent<Transform>>())
transformRef.Value.Translate(0,1,0);