Advanced Job Features¶
This page covers advanced job APIs for manual job scheduling and low-level component access. For the basics of running jobs with [WrapAsJob] and manual job structs, see Jobs & Burst.
FromWorld — Auto-Wiring Job Fields¶
The [FromWorld] attribute marks fields on a job struct to be automatically populated from the world before scheduling:
[BurstCompile]
partial struct MyJob : IJobFor
{
[FromWorld(Tag = typeof(GameTags.Player))]
public NativeComponentBufferRead<Position> Positions;
[FromWorld(Tag = typeof(GameTags.Player))]
public NativeComponentBufferWrite<Velocity> Velocities;
[FromWorld]
public NativeWorldAccessor NativeWorld;
public void Execute(int index)
{
Velocities[index].Value += new float3(0, -9.8f, 0) * NativeWorld.DeltaTime;
}
}
Supported Field Types¶
| Field Type | Purpose | Requires Tag? |
|---|---|---|
NativeComponentBufferRead<T> |
Read-only component buffer for a group | Yes |
NativeComponentBufferWrite<T> |
Writable component buffer for a group | Yes |
NativeComponentLookupRead<T> |
Read-only lookup across multiple groups | Yes |
NativeComponentLookupWrite<T> |
Writable lookup across multiple groups | Yes |
NativeSetRead<TSet> |
Read-only set access | No |
NativeSetWrite<TSet> |
Writable set access | No |
NativeWorldAccessor |
Job-safe world operations | No |
Group |
Group identifier | Yes |
Tag Resolution¶
Fields that require a tag scope (buffers, lookups, Group) can get their tags in two ways:
- Inline — specify
TagorTagsdirectly on the attribute:[FromWorld(Tag = typeof(GameTags.Player))]. The tag is baked into the generated code. - At schedule time — omit
Tag/Tags, and the generatedScheduleParallelmethod will include aTagSetparameter that the caller must provide:
[BurstCompile]
partial struct FlexibleJob : IJobFor
{
[FromWorld] // No inline tag — becomes a schedule parameter
public NativeComponentBufferWrite<Position> Positions;
public void Execute(int index) { ... }
}
// Caller provides the tag at schedule time
new FlexibleJob().ScheduleParallel(World, TagSet<GameTags.Player>.Value);
This is useful when if the tagset being operated on is not known until runtime, or if you want to reuse the same job struct for multiple tag scopes. The generated ScheduleParallel method will have a parameter for each [FromWorld] field that doesn't specify tags inline.
Fields that don't require tags (NativeSetRead, NativeSetWrite, NativeWorldAccessor) are populated automatically and never generate schedule parameters.
Native Component Access¶
Buffers — Single Group¶
For iterating all entities in one group:
NativeComponentBufferRead<Position> positions; // Read-only
NativeComponentBufferWrite<Velocity> velocities; // Read-write
// Access by index
ref readonly Position pos = ref positions[i];
ref Velocity vel = ref velocities[i];
Lookups — Cross-Group¶
For accessing components on arbitrary entities across groups:
NativeComponentLookupRead<Health> healthLookup;
NativeComponentLookupWrite<Damage> damageLookup;
// Access by EntityIndex
ref readonly Health hp = ref healthLookup[entityIndex];
ref Damage dmg = ref damageLookup[entityIndex];
// Check existence
if (healthLookup.Exists(entityIndex)) { ... }
if (healthLookup.TryGet(entityIndex, out Health hp)) { ... }
Native Set Operations¶
Sets can be read and modified from jobs:
[FromWorld]
NativeSetRead<HighlightedParticle> highlightedRead;
[FromWorld]
NativeSetWrite<HighlightedParticle> highlightedWrite;
// Check membership
bool isHighlighted = highlightedRead.Exists(entityIndex);
// Modify (thread-safe, immediate within job)
highlightedWrite.AddImmediate(entityIndex);
highlightedWrite.RemoveImmediate(entityIndex);
External Job Tracking¶
In the rare case where a job is scheduled manually without using the Trecs source generator (e.g., a third-party job or a custom scheduling pattern), you can register it with the world so the dependency tracker knows about them, using TrackExternalJob:
JobHandle handle = myJob.Schedule(count, batchSize);
World.TrackExternalJob(handle)
.Writes<Position>(TagSet<GameTags.Player>.Value)
.Reads<Velocity>(TagSet<GameTags.Player>.Value);
To force-complete jobs before main-thread access: