Game.Simulation.CommercialAISystem
Assembly: Assembly-CSharp (game code)
Namespace: Game.Simulation
Type: class
Base: GameSystemBase
Summary:
CommercialAISystem updates commercial (service/retail) company AI logic on a periodic schedule. It schedules a parallel IJobChunk (CommercialCompanyAITickJob) that iterates over company entities and:
- adjusts the WorkProvider.max workers based on property/service availability and building capacity,
- enables PropertySeeker on companies that can afford to look for property (based on company worth),
- deletes very poor companies that have no renters and are below worth thresholds,
- uses many Prefab/Component lookups (building, prefab, service company data, resource data, trucks, layouts) and the ResourceSystem prefabs.
The system requires EconomyParameterData and company-related components and synchronizes with the simulation frame using UpdateFrame and an EndFrameBarrier command buffer.
Fields
-
public static readonly int kUpdatesPerDay = 32
Constant: number of updates per in-game day used to compute update frames. -
public static readonly int kLowestCompanyWorth = -10000
Constant: threshold for deleting very poor companies (companies below this total worth may be removed). -
public static readonly int kMinimumEmployee = 5
Constant: minimum employee count used when adjusting WorkProvider.m_MaxWorkers. -
private EntityQuery m_EconomyParameterQuery
Query used to fetch the EconomyParameterData singleton required for job parameters. -
private SimulationSystem m_SimulationSystem
Reference to the SimulationSystem (used to compute update frames). -
private EndFrameBarrier m_EndFrameBarrier
Reference to EndFrameBarrier used to create an EntityCommandBuffer.ParallelWriter for safe structural changes from the job. -
private ResourceSystem m_ResourceSystem
Reference to the ResourceSystem (provides resource prefab access and reader registrations). -
private EntityQuery m_CompanyQuery
Query selecting commercial/service companies to be processed by the job. It requires ServiceAvailable, WorkProvider, UpdateFrame, PrefabRef, Resources and excludes Created/Deleted. -
private TypeHandle __TypeHandle
Internal cached handles for entity/component/buffer/shared component lookups used when scheduling the job.
Properties
- None (the system exposes no public properties).
Constructors
public CommercialAISystem()
Default constructor. Systems in this codebase typically rely on OnCreate for initialization rather than constructor logic.
Methods
-
public override int GetUpdateInterval(SystemUpdatePhase phase)
Returns the update interval in ticks for scheduling this system. Uses kUpdatesPerDay and a hardcoded factor so the system runs periodically across the game's update frames. -
protected override void OnCreate()
Initializes the system: obtains references to SimulationSystem, EndFrameBarrier, ResourceSystem; creates EntityQueries (m_EconomyParameterQuery, m_CompanyQuery); marks required queries for update (RequireForUpdate) so the system only runs when relevant data exists. -
protected override void OnStopRunning()
Teardown hook. Currently calls base.OnStopRunning() and has no additional logic, but kept for lifecycle completeness. -
protected override void OnUpdate()
Main update entry. Computes the current update frame index via SimulationUtils.GetUpdateFrame, creates and populates a CommercialCompanyAITickJob with component/type handles, prefab lookups, resource prefabs, random seed and EconomyParameterData, then schedules the job in parallel using JobChunkExtensions.ScheduleParallel. Adds the produced job dependency to the EndFrameBarrier and registers a prefabs reader with the ResourceSystem.
Key behaviors performed by the scheduled job: - Filters chunks by matching UpdateFrame.shared component index to the computed update frame. - For each company entity: - Reads prefab and service/company data. - If the company is a renter (PropertyRenter present), compute suitable maximum workers using CompanyUtils.GetCommercialMaxFittingWorkers and adjust WorkProvider.m_MaxWorkers up or down depending on service availability and current worker counts. - For entities without an enabled PropertySeeker, occasionally (randomized) checks company worth via EconomyUtils.GetCompanyTotalWorth. If worth > kLowestCompanyWorth, enables PropertySeeker; otherwise, if the company is not a renter, marks the entity Deleted via command buffer. - Uses many read-only lookups (building/prefab/commodity data, layouts, trucks) and buffer accessors for company resources, employees and owned vehicles.
-
private void __AssignQueries(ref SystemState state)
Internal method used by compiler-generated OnCreateForCompiler to initialize/validate query state. This implementation currently creates and disposes an empty query builder (compiler artifact). -
protected override void OnCreateForCompiler()
Compiler-time initialization: assigns query handles and calls __TypeHandle.__AssignHandles to populate internal type handles for later scheduling. -
Nested type:
CommercialCompanyAITickJob : IJobChunk
Job struct used to process company archetype chunks in parallel. Contains handles for EntityType, ComponentType and BufferType, many ComponentLookup/BufferLookup instances, RandomSeed, EconomyParameterData, update frame index and an EntityCommandBuffer.ParallelWriter. Its Execute method contains the per-entity logic described above. -
Nested type:
TypeHandle
Compiler helper struct that stores component/entity/buffer/shared component handles and provides __AssignHandles(ref SystemState) to fetch those handles from the system state.
Usage Example
// This system is a world/system class: it initializes itself in OnCreate and schedules a job in OnUpdate.
// Example showing how OnCreate sets up required queries (simplified - the real system does more):
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
m_SimulationSystem = World.GetOrCreateSystemManaged<SimulationSystem>();
m_EndFrameBarrier = World.GetOrCreateSystemManaged<EndFrameBarrier>();
m_ResourceSystem = World.GetOrCreateSystemManaged<ResourceSystem>();
m_EconomyParameterQuery = GetEntityQuery(ComponentType.ReadOnly<EconomyParameterData>());
m_CompanyQuery = GetEntityQuery(
ComponentType.ReadOnly<ServiceAvailable>(),
ComponentType.ReadWrite<WorkProvider>(),
ComponentType.ReadOnly<UpdateFrame>(),
ComponentType.ReadOnly<PrefabRef>(),
ComponentType.ReadOnly<Resources>(),
ComponentType.ReadOnly<Game.Companies.ProcessingCompany>(),
ComponentType.ReadOnly<TradeCost>(),
ComponentType.Exclude<Created>(),
ComponentType.Exclude<Deleted>()
);
RequireForUpdate(m_CompanyQuery);
RequireForUpdate(m_EconomyParameterQuery);
}
Notes and modding considerations: - The system relies heavily on computed update frames (UpdateFrame shared component). If you add or change update frame logic you must ensure companies receive the correct UpdateFrame values. - The job performs structural changes (AddComponent/Delete/SetComponentEnabled) via an EntityCommandBuffer.ParallelWriter created from EndFrameBarrier — modifications are deferred to end of frame. - Many lookups are read-only; adding new writable component usage would require altering the TypeHandle and job data accordingly. - If you want to modify company AI behavior, consider creating a patch or custom system that runs at a different update interval or intercepts the relevant components (WorkProvider, PropertySeeker, PropertyRenter, ServiceAvailable).