Game.Serialization.DataMigration.HomelessAndWorkerFixSystem
Assembly: Game
Namespace: Game.Serialization.DataMigration
Type: class
Base: GameSystemBase
Summary:
A compiler-generated data-migration system that fixes mismatches introduced by older save formats related to homeless households, worker components and missing PropertySeeker components. When a loaded save does not contain the FormatTags.HomelessAndWorkerFix tag, this system:
- Removes Worker components from entities that reference workplaces which do not list them as employees.
- Marks homeless households for deletion.
- Adds a disabled PropertySeeker component to households and companies that are missing it.
- Removes PropertyOnMarket from abandoned properties.
The system uses ECS chunk jobs (Burst-compiled) and issues structural changes through a DeserializationBarrier command buffer to ensure safe, threaded modifications during load.
Fields
-
private LoadGameSystem m_LoadGameSystem
Reference to the load-game system; used to inspect the save format and determine whether migration is required. -
private DeserializationBarrier m_DeserializationBarrier
Barrier system used to create an EntityCommandBuffer (parallel writer) for performing structural changes safely from jobs. -
private EntityQuery m_WorkerQuery
Query selecting entities with the Worker component. Used to find workers to validate against Employee buffers. -
private EntityQuery m_HomelessQuery
Query selecting entities marked with HomelessHousehold; used to delete homeless households when migration is applied. -
private EntityQuery m_NeedAddPropertySeekerQuery
Query selecting household or company entities that do not have a PropertySeeker component (Any: Household or CompanyData, None: PropertySeeker). Used to add a disabled PropertySeeker where missing. -
private EntityQuery m_AbandonedPropertyQuery
Query selecting entities with Abandoned; used to remove PropertyOnMarket from abandoned properties. -
private TypeHandle __TypeHandle
Private struct bundling EntityTypeHandle, ComponentTypeHandle, and BufferLookup used by the chunk jobs. Populated via __AssignHandles in OnCreateForCompiler. -
Nested types (private):
WorkerFixJob
(private struct, BurstCompile, IJobChunk)
Iterates chunks of Worker components and removes Worker from entities whose workplace's Employee buffer does not reference that worker entity.AddPropertySeekerJob
(private struct, BurstCompile, IJobChunk)
Iterates chunks of entities and adds (and disables) a PropertySeeker component via the parallel command buffer.TypeHandle
(private struct)
Helper to cache type handles and buffer lookups; provides __AssignHandles(ref SystemState).
Properties
- None (no public properties exposed by this system)
Constructors
public HomelessAndWorkerFixSystem()
Default constructor (compiler-generated). The real initialization of queries and type handles happens in OnCreate / OnCreateForCompiler.
Methods
protected override void OnCreate()
Initializes references and entity queries:- Resolves LoadGameSystem and DeserializationBarrier from the World.
-
Creates queries for Worker, HomelessHousehold, Abandoned, and the Any(Household, CompanyData) && None(PropertySeeker) set.
-
protected override void OnUpdate()
Main runtime logic executed each frame during load: - If the save format does NOT have FormatTags.HomelessAndWorkerFix, performs migration steps:
- Schedules WorkerFixJob (parallel) to remove invalid Worker components, using DeserializationBarrier command buffer.
- Adds Deleted component to homeless households (deferred structural change).
- Schedules AddPropertySeekerJob (parallel) to add disabled PropertySeeker components to households/companies lacking them.
- Removes PropertyOnMarket from abandoned properties via immediate EntityManager.RemoveComponent.
-
Adds the job handles to the DeserializationBarrier to ensure producer-consumer safety and updates base.Dependency accordingly.
-
private void __AssignQueries(ref SystemState state)
Called by the compiler-generated OnCreateForCompiler to assign any compile-time query initialization; here it only creates and disposes an EntityQueryBuilder temporary (present for generated code patterns). -
protected override void OnCreateForCompiler()
Compiler helper that calls __AssignQueries and __TypeHandle.__AssignHandles to set up handles used by job scheduling. -
TypeHandle.__AssignHandles(ref SystemState state)
Assigns and caches EntityTypeHandle, ComponentTypeHandle(read-only), and BufferLookup (read-only) from the provided SystemState. This method is AggressiveInlining and used by OnCreateForCompiler. -
WorkerFixJob.Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
For each entity in the chunk: - Retrieves the Worker component and its associated workplace entity.
- Checks whether the workplace has an Employee dynamic buffer and whether that buffer contains an Employee entry that references the worker entity.
-
If the worker is not present in the workplace’s Employee buffer, schedules a removal of the Worker component for that entity via the parallel command buffer.
-
AddPropertySeekerJob.Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
For each entity in the chunk: - Adds a PropertySeeker component and immediately sets it disabled (SetComponentEnabled
(..., value: false)) using the parallel command buffer.
Notes: - Jobs are Burst-compiled and operate over archetype chunks for performance. - Structural changes (add/remove components) are performed via DeserializationBarrier's EntityCommandBuffer to avoid modifying entity archetypes directly from jobs. - The system is guarded by the LoadGameSystem context FormatTags check so that migration only runs when loading older saves.
Usage Example
This system runs automatically as part of the world’s system list during loading. You normally do not need to call it directly. Example (illustrative) of how the migration behavior is gated by the save format tag:
// Simplified conceptual example: the system checks if the loaded save format has the tag.
// If not, it will schedule jobs that fix Worker components and add missing PropertySeeker components.
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
m_LoadGameSystem = World.GetOrCreateSystemManaged<LoadGameSystem>();
m_DeserializationBarrier = World.GetOrCreateSystemManaged<DeserializationBarrier>();
m_WorkerQuery = GetEntityQuery(ComponentType.ReadOnly<Worker>());
// ... other queries set up
}
[Preserve]
protected override void OnUpdate()
{
if (!m_LoadGameSystem.context.format.Has(FormatTags.HomelessAndWorkerFix))
{
// WorkerFixJob and AddPropertySeekerJob are scheduled, and homeless households are marked Deleted.
}
}
If you are modding save behavior or manipulating citizen/workplace data during load, be aware that this system may remove Worker components or add disabled PropertySeeker components when loading older saves — ensure your mod accounts for these structural changes or sets the appropriate FormatTags when producing saves.