Skip to content

Game.LaneDirectionNetObjectSystem

Assembly: Game (assembly containing game systems; likely Assembly-CSharp)
Namespace: Game.Serialization.DataMigration

Type: class

Base: GameSystemBase

Summary:
LaneDirectionNetObjectSystem is a data-migration ECS system used during game load to retrofit older saves with the NetObject component for prefabs that contain lane-direction data. When loading a save that predates the Version.laneDirectionNetObject migration, this system finds static object entities (that are not already NetObject, Plant, or Building), checks their PrefabRef for the presence of LaneDirectionData, and adds Game.Objects.NetObject and Updated components via a parallel EntityCommandBuffer to ensure those entities are upgraded to the new representation safely during deserialization. The system uses a DeserializationBarrier to synchronize and record the producer job handle.


Fields

  • private LoadGameSystem m_LoadGameSystem
    Used to inspect the current load context and save version. The system checks m_LoadGameSystem.context.version against Version.laneDirectionNetObject to decide whether migration is needed.

  • private DeserializationBarrier m_DeserializationBarrier
    Barrier system used to produce an EntityCommandBuffer (as a ParallelWriter) and to register the job handle so structural changes are synchronized with deserialization.

  • private EntityQuery m_Query
    Query that selects entities to examine: entities with Object and Static components, excluding Game.Objects.NetObject, Plant, and Building.

  • private TypeHandle __TypeHandle
    Container struct that caches EntityTypeHandle, PrefabRef ComponentTypeHandle, and a ComponentLookup for use in the job. Populated via __AssignHandles when the system is created for the compiler.

  • private struct LaneDirectionNetObjectJob (nested)
    Burst-compiled IJobChunk that iterates matching chunks; reads PrefabRef and uses the component lookup to test whether the prefab contains LaneDirectionData. If so, it enqueues AddComponent commands (Game.Objects.NetObject and Updated) to the parallel command buffer for that entity.

  • private struct TypeHandle (nested)
    Holds the read-only handles / lookups used by the job and provides __AssignHandles(ref SystemState) to initialize them.

Properties

  • None (this system exposes no public properties)

Constructors

  • public LaneDirectionNetObjectSystem()
    Default constructor. The class is marked with [Preserve] on lifecycle methods to ensure they are not stripped.

Methods

  • protected override void OnCreate()
    Initializes references to required systems and builds the EntityQuery:
  • Gets or creates LoadGameSystem and DeserializationBarrier from World.
  • Constructs the query: ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.Exclude(), ComponentType.Exclude(), ComponentType.Exclude(). This prepares the system to find candidate entities that need migration.

  • protected override void OnUpdate()
    Main migration logic:

  • Checks if the current save version is older than Version.laneDirectionNetObject (i.e., migration required) and that the query is not empty.
  • If migration is required, schedules LaneDirectionNetObjectJob in parallel over m_Query.
  • Provides the job with entity/prefab type handles and a ComponentLookup, and a parallel command buffer from m_DeserializationBarrier.
  • Adds the returned JobHandle to the DeserializationBarrier and sets base.Dependency so other work can chain correctly.

  • protected override void OnCreateForCompiler()
    Compiler-time initialization path:

  • Calls __AssignQueries and __TypeHandle.__AssignHandles(ref base.CheckedStateRef) to prepare query and cached type handles for generated/compiled systems.

  • private void __AssignQueries(ref SystemState state)
    Generated helper that constructs any query builders used by the compiler. In this class it currently calls new EntityQueryBuilder(Allocator.Temp).Dispose(); (no extra queries beyond m_Query which is set in OnCreate).

  • private struct LaneDirectionNetObjectJob.Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
    Job chunk execution:

  • Reads NativeArray and NativeArray for the chunk.
  • Iterates entities in the chunk, for each prefabRef checks m_PrefabLaneDirection.HasComponent(prefabRef.m_Prefab).
  • If the prefab has LaneDirectionData, enqueues m_CommandBuffer.AddComponent to add default(Game.Objects.NetObject) and default(Updated) to the entity.
  • The job is Burst-compiled and scheduled in parallel for performance and safety during load-time migration.
  • Notes on threading and safety: - The job uses read-only type handles and a ComponentLookup (read-only) plus an EntityCommandBuffer.ParallelWriter for structural modifications. - The DeserializationBarrier is used to safely integrate structural changes with the rest of deserialization work.

    Usage Example

    // This system runs automatically as part of the game's ECS world during load.
    // Example: simplified equivalent of the OnUpdate scheduling logic used by the system.
    
    [Preserve]
    protected override void OnUpdate()
    {
        // If the save version is older than the laneDirectionNetObject migration
        // and there are matching entities, schedule the parallel job to add components.
        if (!(m_LoadGameSystem.context.version >= Version.laneDirectionNetObject) && !m_Query.IsEmptyIgnoreFilter)
        {
            var job = new LaneDirectionNetObjectJob
            {
                m_EntityType = InternalCompilerInterface.GetEntityTypeHandle(ref __TypeHandle.__Unity_Entities_Entity_TypeHandle, ref base.CheckedStateRef),
                m_PrefabRefType = InternalCompilerInterface.GetComponentTypeHandle(ref __TypeHandle.__Game_Prefabs_PrefabRef_RO_ComponentTypeHandle, ref base.CheckedStateRef),
                m_PrefabLaneDirection = InternalCompilerInterface.GetComponentLookup(ref __TypeHandle.__Game_Prefabs_LaneDirectionData_RO_ComponentLookup, ref base.CheckedStateRef),
                m_CommandBuffer = m_DeserializationBarrier.CreateCommandBuffer().AsParallelWriter()
            };
    
            JobHandle handle = JobChunkExtensions.ScheduleParallel(job, m_Query, base.Dependency);
            m_DeserializationBarrier.AddJobHandleForProducer(handle);
            base.Dependency = handle;
        }
    }
    

    Additional tips for modders: - If you add new components representing migration state, ensure they are added via the DeserializationBarrier / command buffers to avoid structural-change race conditions during load. - Use ComponentLookup when you need to test whether a prefab (entity) type has a particular component at job time. - Respect the version gating: migrations should run only for versions older than the migration version marker.