Game.Objects.PlaceholderSystem
Assembly: Assembly-CSharp.dll (game code)
Namespace: Game.Objects
Type: class (public)
Base: GameSystemBase
Summary:
PlaceholderSystem is an ECS GameSystem used during New Game initialization to replace "placeholder" object entities with actual creatable objects (CreationDefinition entities) based on prefab placeholder definitions and spawn rules. It runs a parallel IJobChunk (PlaceholderJob) that scans entities with PrefabRef / Owner / Transform and associated buffers, chooses a variation by probability and requirements (theme and prefab requirements), and emits CreationDefinition entities via an EntityCommandBuffer. The system relies on LoadGameSystem and CityConfigurationSystem to determine when to run (only on NewGame) and uses RandomSeed to pick variations deterministically.
Fields
-
private LoadGameSystem m_LoadGameSystem
Reference to the game's LoadGameSystem (retrieved in OnCreate). Used to check load context (Purpose.NewGame) before performing placeholder processing. -
private CityConfigurationSystem m_CityConfigurationSystem
Reference to CityConfigurationSystem (retrieved in OnCreate). Used to obtain the default theme used when evaluating prefab requirements. -
private EntityQuery m_EntityQuery
EntityQuery built to require Placeholder components for updating this system. The system calls RequireForUpdate(m_EntityQuery) in OnCreate so it only runs when placeholders exist. -
private TypeHandle __TypeHandle
Internal container for all Entity/Component/Buffer type handles used by the job. Populated by __AssignHandles during system setup (OnCreateForCompiler). -
(nested)
private struct PlaceholderJob : IJobChunk
The Burst-compiled job that iterates matching chunks and performs the placeholder-to-creation conversion. See Methods section for details of its fields and behavior. -
(nested)
private struct TypeHandle
Helper struct that stores the various ComponentTypeHandle / BufferTypeHandle / ComponentLookup / BufferLookup used by PlaceholderJob. Has an __AssignHandles method to initialize handles from SystemState.
Properties
- This system exposes no public properties.
Constructors
public PlaceholderSystem()
Default parameterless constructor. The system is preserved for the managed world by the [Preserve] attribute on lifecycle methods; construction itself does not perform initialization beyond base construction.
Methods
protected override void OnCreate()
Called when the system is created. It:- Calls base.OnCreate().
- Retrieves and caches m_LoadGameSystem and m_CityConfigurationSystem from the world.
-
Builds an EntityQuery for Placeholder components and calls RequireForUpdate(m_EntityQuery) so the system only updates when placeholder entities are present.
-
protected override void OnUpdate()
Main update logic. It: - Checks if m_LoadGameSystem.context.purpose == Purpose.NewGame. The placeholder replacement runs only on a new game load.
- If NewGame, creates an EntityCommandBuffer (TempJob) and schedules the Burst-compiled PlaceholderJob as a parallel JobChunk, providing all necessary handles, lookups, RandomSeed, theme and the command buffer writer.
-
Completes the job, plays back the entity command buffer to the EntityManager and disposes the buffer.
-
protected override void OnCreateForCompiler()
Compiler helper invoked by generated code: calls __AssignQueries and initializes type handles via __TypeHandle.__AssignHandles. Required to prepare internal handles for the job. -
private void __AssignQueries(ref SystemState state)
Internal method to initialize any queries; the implementation shown creates and disposes an EntityQueryBuilder(Allocator.Temp) (likely placeholder/instrumentation in compiled code). -
(nested) PlaceholderJob.Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask) : void
The job's chunk execution logic: - Retrieves Owner and Transform arrays for the chunk and handles owner indirection resolution (follows Owner.m_Owner chain via m_OwnerData lookup until top-most owner).
- If it finds an owner entity that does not have a Placeholder component, it adds an Updated component to that owner via command buffer.
- Otherwise it iterates matching PrefabRef entries in the chunk:
- For each PrefabRef it tries to pick a placeholder variation by iterating a PlaceholderObjectElement buffer (m_PrefabPlaceholderElements) and using GetVariationProbability to get the numeric weight and to filter out variations that don't satisfy requirements.
- Uses a Random seeded with RandomSeed to choose one variation weighted by probability.
- If a variation was selected (entity != Entity.Null), it constructs a CreationDefinition with flags (Permanent | Native), assigns the chosen prefab, sets a random seed, and attempts to set the CreationDefinition.m_Owner if an Owner exists and is resolved to a top owner that still has a Placeholder.
- Creates a new entity via command buffer, adds CreationDefinition, ObjectDefinition (position/rotation copied from Transform if available), copies area nodes (Node buffer) if present, and marks the creation entity with Updated. Finally, marks the original placeholder entity with Deleted.
- If no variation selected, it simply marks the placeholder entity with Deleted.
-
Operates via EntityCommandBuffer.ParallelWriter so it is safe to run in parallel.
-
(nested) PlaceholderJob.GetVariationProbability(PlaceholderObjectElement placeholder, out int probability) : bool
- Default probability = 100.
- If the prefab has ObjectRequirementElement buffers, it iterates groups of requirements and checks whether any requirement in a group matches the current theme (m_Theme). If any requirement-group is not satisfied, it returns false to indicate the variation is invalid.
- If SpawnableObjectData exists on the prefab, it uses componentData.m_Probability as the probability value.
-
Returns true if the variation is allowed (and sets probability), false if it is not allowed due to unsatisfied requirements.
-
(nested) TypeHandle.__AssignHandles(ref SystemState state)
Initializes all internal handles used by the job: - Gets EntityTypeHandle, ComponentTypeHandle
, ComponentTypeHandle , ComponentTypeHandle , BufferTypeHandle , and ComponentLookup/BufferLookup for Placeholder, Owner, SpawnableObjectData, PlaceholderObjectElement, ObjectRequirementElement.
Notes / Behavior details: - The job is Burst-compiled and uses Unity.Entities IJobChunk to process entities efficiently in chunks. - Random selection is weighted: the code sums weights and uses random.NextInt(total) < weight to pick variations in a typical reservoir-like selection. - The system resolves owner chains: it follows Owner components until it reaches a top-level owner and uses that owner for Created entities or to detect whether a placeholder should be replaced with Updated. - Created entities are flagged Permanent and Native in CreationDefinition flags. - The job both creates new entities (CreationDefinition) and marks the original placeholder with Deleted so they are removed. - All entity modifications are done via EntityCommandBuffer to be safe from inside jobs.
Usage Example
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// Cache systems we need
m_LoadGameSystem = World.GetOrCreateSystemManaged<LoadGameSystem>();
m_CityConfigurationSystem = World.GetOrCreateSystemManaged<CityConfigurationSystem>();
// Only run this system when Placeholder components exist in the world
m_EntityQuery = GetEntityQuery(ComponentType.ReadOnly<Placeholder>());
RequireForUpdate(m_EntityQuery);
}
[Preserve]
protected override void OnUpdate()
{
// This system runs its placeholder-to-creation job only when starting a new game
if (m_LoadGameSystem.context.purpose == Purpose.NewGame)
{
var ecb = new EntityCommandBuffer(Allocator.TempJob);
// Fill and schedule PlaceholderJob (job setup omitted for brevity)
// Complete, playback and dispose the command buffer as shown in the game code.
}
}
This system is intended for modders who need to understand how placeholder prefabs are resolved at new game start, how requirements and probabilities are evaluated, and where to hook or extend behavior (e.g., by modifying placeholder buffers, SpawnableObjectData, or object requirement elements).