Game.Buildings.SchoolUpdatedSystem
Assembly:
Assembly-CSharp (game/main assembly for Cities: Skylines 2)
Namespace:
Game.Buildings
Type:
public class
Base:
GameSystemBase
Summary:
SchoolUpdatedSystem is an ECS system responsible for keeping student buffers on School entities consistent and for cleaning up student-related components when a school is deleted. It uses two Burst-compiled IJobChunk jobs:
- SchoolUpdatedJob: iterates school entities that were marked as having their students modified (StudentsRemoved) and removes any Student buffer entries that no longer reference the school; also clears the StudentsRemoved tag on the school.
- SchoolDeletedJob: iterates school entities that are marked Deleted and removes the Game.Citizens.Student component (and, when appropriate, the TravelPurpose component) from student entities that referenced that school.
The system schedules jobs in parallel and issues structural changes through a ModificationEndBarrier (EntityCommandBuffer.ParallelWriter). It caches type handles via an inner TypeHandle struct for efficient access to EntityTypeHandle, BufferTypeHandle
Fields
-
private ModificationEndBarrier m_ModificationBarrier
This barrier/system is used to create an EntityCommandBuffer.ParallelWriter for safely issuing structural changes (component removals) from jobs scheduled by this system. -
private EntityQuery m_UpdatedSchoolQuery
Query selecting School entities that have a Student buffer and the StudentsRemoved tag, excluding Temp and Deleted. Used to drive SchoolUpdatedJob. -
private EntityQuery m_DeletedSchoolQuery
Query selecting School entities that have a Student buffer and are marked Deleted (excluding Temp). Used to drive SchoolDeletedJob. -
private TypeHandle __TypeHandle
Private struct instance that stores cached type handles (EntityTypeHandle, BufferTypeHandle, ComponentLookup , ComponentLookup ). __TypeHandle.__AssignHandles is called to initialize these handles for the current SystemState. -
(nested types)
SchoolUpdatedJob
,SchoolDeletedJob
,TypeHandle
Private nested structs used by the system. The jobs implement IJobChunk and are Burst compiled. TypeHandle holds & assigns required handles.
Properties
- No public properties.
(The system uses private fields and cached type handles; all scheduling and command buffers are managed inside OnUpdate.)
Constructors
public SchoolUpdatedSystem()
Default constructor. The class relies on OnCreate to initialize queries and barriers rather than doing work in the ctor.
Methods
protected override void OnCreate()
Initializes m_ModificationBarrier by fetching/creating the ModificationEndBarrier system from the world. Creates two EntityQuery instances:- m_UpdatedSchoolQuery: School + Student + StudentsRemoved, excluding Temp and Deleted
-
m_DeletedSchoolQuery: School + Student + Deleted, excluding Temp Calls RequireAnyForUpdate with those queries so the system only runs when either query has matching entities.
-
protected override void OnUpdate()
Main scheduling method. For each non-empty query: - Fills a jobData struct (SchoolUpdatedJob or SchoolDeletedJob) with type handles obtained via InternalCompilerInterface and a ParallelWriter from m_ModificationBarrier.
- Schedules the job with JobChunkExtensions.ScheduleParallel on the matching query and appends the returned JobHandle to base.Dependency.
- Registers the job handle with m_ModificationBarrier via AddJobHandleForProducer so the barrier waits for producer jobs before applying structural changes.
SchoolUpdatedJob behavior:
- For each school entity, iterates its DynamicBuffer
SchoolDeletedJob behavior:
- For each deleted school entity, iterates its DynamicBuffer
-
protected override void OnCreateForCompiler()
Helper for generated/compiled code paths: calls __AssignQueries and __TypeHandle.__AssignHandles with base.CheckedStateRef. Ensures the generated type handles and queries are wired up for AOT/IL2CPP/compiler scenarios. -
private void __AssignQueries(ref SystemState state)
Called by OnCreateForCompiler; currently contains an EntityQueryBuilder(Allocator.Temp).Dispose() placeholder. Its purpose is to satisfy generated code patterns and can be a hook for query initialization by the compiler. -
private struct TypeHandle.__AssignHandles(ref SystemState state)
Assigns: - EntityTypeHandle via state.GetEntityTypeHandle()
- BufferTypeHandle
via state.GetBufferTypeHandle () - ComponentLookup
via state.GetComponentLookup (isReadOnly: true) - ComponentLookup
via state.GetComponentLookup (isReadOnly: true)
These cached handles are then used when creating jobData to avoid repeatedly fetching handles each frame.
Usage Example
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
m_ModificationBarrier = base.World.GetOrCreateSystemManaged<ModificationEndBarrier>();
m_UpdatedSchoolQuery = GetEntityQuery(
ComponentType.ReadOnly<School>(),
ComponentType.ReadOnly<Student>(),
ComponentType.ReadOnly<StudentsRemoved>(),
ComponentType.Exclude<Temp>(),
ComponentType.Exclude<Deleted>());
m_DeletedSchoolQuery = GetEntityQuery(
ComponentType.ReadOnly<School>(),
ComponentType.ReadOnly<Student>(),
ComponentType.ReadOnly<Deleted>(),
ComponentType.Exclude<Temp>());
RequireAnyForUpdate(m_UpdatedSchoolQuery, m_DeletedSchoolQuery);
}
[Preserve]
protected override void OnUpdate()
{
if (!m_UpdatedSchoolQuery.IsEmptyIgnoreFilter)
{
var jobData = new SchoolUpdatedJob
{
m_EntityType = InternalCompilerInterface.GetEntityTypeHandle(ref __TypeHandle.__Unity_Entities_Entity_TypeHandle, ref base.CheckedStateRef),
m_StudentType = InternalCompilerInterface.GetBufferTypeHandle(ref __TypeHandle.__Game_Buildings_Student_RW_BufferTypeHandle, ref base.CheckedStateRef),
m_Students = InternalCompilerInterface.GetComponentLookup(ref __TypeHandle.__Game_Citizens_Student_RO_ComponentLookup, ref base.CheckedStateRef),
m_CommandBuffer = m_ModificationBarrier.CreateCommandBuffer().AsParallelWriter()
};
base.Dependency = JobChunkExtensions.ScheduleParallel(jobData, m_UpdatedSchoolQuery, base.Dependency);
m_ModificationBarrier.AddJobHandleForProducer(base.Dependency);
}
if (!m_DeletedSchoolQuery.IsEmptyIgnoreFilter)
{
var jobData2 = new SchoolDeletedJob
{
m_EntityType = InternalCompilerInterface.GetEntityTypeHandle(ref __TypeHandle.__Unity_Entities_Entity_TypeHandle, ref base.CheckedStateRef),
m_StudentType = InternalCompilerInterface.GetBufferTypeHandle(ref __TypeHandle.__Game_Buildings_Student_RW_BufferTypeHandle, ref base.CheckedStateRef),
m_Purposes = InternalCompilerInterface.GetComponentLookup(ref __TypeHandle.__Game_Citizens_TravelPurpose_RO_ComponentLookup, ref base.CheckedStateRef),
m_Students = InternalCompilerInterface.GetComponentLookup(ref __TypeHandle.__Game_Citizens_Student_RO_ComponentLookup, ref base.CheckedStateRef),
m_CommandBuffer = m_ModificationBarrier.CreateCommandBuffer().AsParallelWriter()
};
base.Dependency = JobChunkExtensions.ScheduleParallel(jobData2, m_DeletedSchoolQuery, base.Dependency);
m_ModificationBarrier.AddJobHandleForProducer(base.Dependency);
}
}
Notes and tips for modders: - The system uses command buffers (ModificationEndBarrier) to perform structural changes from jobs. If you add new jobs that remove or add components, use the same pattern to avoid structural changes inside a job without a command buffer. - Ensure your Student buffer entries are kept consistent with the Game.Citizens.Student.m_School field; otherwise the SchoolUpdatedJob will prune them. - If you add additional TravelPurpose states, update SchoolDeletedJob logic accordingly to only remove TravelPurpose when appropriate.