Game.Simulation.MaintenanceVehicleAISystem
Assembly: Assembly-CSharp (game runtime)
Namespace: Game.Simulation
Type: class
Base: GameSystemBase
Summary:
MaintenanceVehicleAISystem is the ECS system responsible for simulating maintenance vehicles in Cities: Skylines 2. It manages per-vehicle logic (pathing, dispatch handling, parking, returning to depot, stopping/starting), converts path/dispatch information into actionable maintenance work, and applies maintenance effects (road wear reduction, park maintenance, vehicle repair). The system uses two Burst-compiled jobs:
- MaintenanceVehicleTickJob (IJobChunk) — per-vehicle tick update: path decisions, selecting/consuming dispatches, preparing maintenance actions, parking & path resets, requesting new targets.
- MaintenanceJob (IJob) — dequeues maintenance actions prepared by the tick job and applies state changes to components (e.g., lane wear, damaged/destroyed vehicles, parks) and creates events.
The system uses EndFrameBarrier and PathfindSetupSystem for scheduling writes and pathfinding setup and relies heavily on Unity.Entities / Burst / jobs and game-specific component data such as MaintenanceVehicle, MaintenanceRequest, MaintenanceConsumer, NetCondition, LaneCondition, etc.
Fields
-
private EndFrameBarrier m_EndFrameBarrier
Reference to the EndFrameBarrier system. Used to create an EntityCommandBuffer for deferred structural changes at end of frame. -
private PathfindSetupSystem m_PathfindSetupSystem
Reference to the Pathfind setup system. Used to enqueue pathfinding requests created by maintenance vehicles. -
private SimulationSystem m_SimulationSystem
Reference to the main simulation system, used to read the simulation frame index. -
private CityConfigurationSystem m_CityConfigurationSystem
Reference to the city configuration (e.g., left-hand traffic flag). -
private EntityQuery m_VehicleQuery
Query selecting maintenance-capable vehicles (CarCurrentLane, Owner, PrefabRef, PathOwner, MaintenanceVehicle, Target, etc.). -
private EntityArchetype m_DamageEventArchetype
Archetype used to create Damage event entities when a vehicle is fully repaired. -
private EntityArchetype m_MaintenanceRequestArchetype
Archetype for maintenance request entities (ServiceRequest + MaintenanceRequest + RequestGroup). -
private EntityArchetype m_HandleRequestArchetype
Archetype for handle-request events (HandleRequest + Event). -
private ComponentTypeSet m_MovingToParkedCarRemoveTypes
ComponentTypeSet of components that must be removed when transitioning a moving vehicle into a parked state (e.g., Moving, PathInformation, ServiceDispatch, etc.). -
private ComponentTypeSet m_MovingToParkedAddTypes
ComponentTypeSet of components to add when parking (ParkedCar, Stopped, Updated). -
private TypeHandle __TypeHandle
Internal container storing Component/Buffer/Entity handles used when scheduling the jobs. -
Nested types (declared as private):
MaintenanceAction
struct — small POD struct used to enqueue actions from the tick job to the maintenance job.MaintenanceActionType
enum — type of action (AddRequest, ParkMaintenance, RoadMaintenance, RepairVehicle, ClearLane, BumpDispatchIndex).MaintenanceVehicleTickJob
— Burst IJobChunk that runs per vehicle chunk and populates action & pathfind queues.MaintenanceJob
— Burst IJob that dequeues actions and applies concrete changes.TypeHandle
— internal mapping of handles (see above).
Properties
- No public properties on this system. Most state is kept in components and small private fields. The scheduling parameters (update interval/offset) are exposed via overrides.
Constructors
public MaintenanceVehicleAISystem()
Default constructor, preserved attribute present. System initialization happens in OnCreate.
Methods
-
public override int GetUpdateInterval(SystemUpdatePhase phase)
Returns 16 — the system executes every 16 simulation frames. -
public override int GetUpdateOffset(SystemUpdatePhase phase)
Returns 7 — offset used for scheduling; pairs with the frame index checks used for request timings. -
[Preserve] protected override void OnCreate()
Initializes system references (EndFrameBarrier, PathfindSetupSystem, SimulationSystem, CityConfigurationSystem), creates the vehicle query and archetypes, sets up component type sets and registers the query via RequireForUpdate. This is where the system ensures it will run only when vehicles exist. -
[Preserve] protected override void OnUpdate()
Main scheduling method: - Creates a NativeQueue
for cross-job communication. - Fills a MaintenanceVehicleTickJob struct with Component/Buffer/Lookup handles and queues (pathfind queue + action queue).
- Fills a MaintenanceJob struct with lookups and the same action queue.
- Schedules the tick job as a parallel JobChunk over m_VehicleQuery.
- Schedules MaintenanceJob (IJob) after the tick job completes.
- Registers the job handles with the PathfindSetupSystem and EndFrameBarrier and updates base.Dependency.
This method orchestrates the two-phase execution: per-vehicle decision-making (parallel) and then single-threaded mutation application.
-
protected override void OnCreateForCompiler()
Internal-on-create used by generated code to assign query/handle state for the compiler (wires TypeHandle). -
private void __AssignQueries(ref SystemState state)
Internal helper used by the generated code to set up queries (no custom behavior in source). -
Many private helpers (used inside MaintenanceVehicleTickJob and MaintenanceJob) — these are the core of the simulation logic:
- Tick / Execute (inside MaintenanceVehicleTickJob) — per-vehicle loop; handles:
- Resetting path on updated path,
- Returning to depot if stuck or pathfind failed,
- Handling path end reached: start maintenance work, select next dispatch, return to depot if none,
- Parking behavior and stopping/starting vehicles,
- Checking & selecting parking spaces,
- Requesting new targets (creating ServiceRequest + MaintenanceRequest entities),
- Preparing maintenance action items onto the NativeQueue
.
- Parking / Stop / Start helpers:
- ParkCar — convert vehicle into ParkedCar, remove moving components, set flags and parked location.
- StopVehicle / StartVehicle — remove/add movement components and set PathfindUpdated flags on lanes.
- Path helpers:
- FindNewPath — builds PathfindParameters and enqueues a pathfinding request via PathfindSetupSystem.
- ResetPath — reset the vehicle path when path updates happen; recomputes path element time and flags.
- EndNavigation — clears navigation buffers and marks end-of-path.
- CheckParkingSpace — validates and updates parking space reservations.
- Dispatch & request helpers:
- CheckServiceDispatches — tries to pick next maintenance requests and adjusts the vehicle's estimate of required maintenance.
- SelectNextDispatch — consumes service dispatch buffer and tries to append/replace path elements, sets target, adjusts car flags, enqueues HandleRequest events.
- RequestTargetIfNeeded — opportunistically creates a MaintenanceRequest entity if vehicle lacks one (uses frameIndex modular checks).
- PreAddMaintenanceRequests / AddMaintenanceRequests / BumpDispatchIndex — walk paths of a request and enqueue AddRequest actions for edge owners (to add maintenance consumer data).
- Maintenance checks and actions:
- CheckMaintenancePresence / CheckMaintenancePresence(Entity) — checks whether a lane or edge needs maintenance and updates waypoint flags & car flags accordingly.
- TryMaintain / TryMaintainLane — decide what maintenance action(s) should be enqueued for the MaintenanceJob (road maintenance, park maintenance, vehicle repair).
- GetWorkingFlags — compute appropriate car working flags based on lane limits & left-hand traffic.
- AddPathElement / FindClosestSidewalk — helpers used when appending paths for edge targets, include logic to insert sidewalks when appropriate.
-
MaintenanceJob.Execute — dequeues MaintenanceAction items and applies actual game state changes:
- AddRequest — set MaintenanceConsumer.request and dispatch index.
- ParkMaintenance — increment park maintenance and vehicle's maintained counters; apply CarFlags etc.
- RoadMaintenance — compute total lane wear, cap maintenance amount, apply MaintainLanes to owner/start/end edges and update NetCondition components.
- RepairVehicle — repair Damaged/Destroyed vehicle data, update flags, possibly create Damage event entity if damage reaches zero, mark ClearingDebris flag when needed.
- ClearLane — notify other maintenance vehicles in lane to mark them ClearChecked (so they stop checking).
- BumpDispatchIndex — increment dispatch index on MaintenanceRequest entities.
-
Nested Job Methods (summarized):
- MaintenanceVehicleTickJob.Execute(...) — chunk-based execution for each vehicle chunk; calls internal Tick.
- MaintenanceVehicleTickJob.Tick(...) — core per-vehicle decision logic (described above).
- MaintenanceJob.MaintainLanes(...) & CalculateTotalLaneWear(...) — helpers to compute and apply wear reduction for lanes.
Usage Example
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// Example from system: get required systems & set up queries / archetypes
m_EndFrameBarrier = base.World.GetOrCreateSystemManaged<EndFrameBarrier>();
m_PathfindSetupSystem = base.World.GetOrCreateSystemManaged<PathfindSetupSystem>();
m_SimulationSystem = base.World.GetOrCreateSystemManaged<SimulationSystem>();
m_CityConfigurationSystem = base.World.GetOrCreateSystemManaged<CityConfigurationSystem>();
// Create archetypes and queries as the system does (simplified)
m_VehicleQuery = GetEntityQuery(ComponentType.ReadWrite<CarCurrentLane>(),
ComponentType.ReadOnly<Owner>(),
ComponentType.ReadOnly<PrefabRef>(),
ComponentType.ReadWrite<PathOwner>(),
ComponentType.ReadWrite<Game.Vehicles.MaintenanceVehicle>(),
ComponentType.ReadWrite<Target>(),
ComponentType.Exclude<Deleted>(),
ComponentType.Exclude<Temp>());
// System will then be scheduled every 16 frames with an offset of 7.
}
Additional notes for modders:
- Scheduling: this system runs every 16 simulation frames (GetUpdateInterval = 16) with offset 7. If you need deterministic interaction, respect that timing or intercept resulting events handled by EndFrameBarrier.
- Interaction points:
- Create a maintenance request by creating an entity with components ServiceRequest, MaintenanceRequest, RequestGroup (see m_MaintenanceRequestArchetype).
- The system enqueues pathfind requests via PathfindSetupSystem; to add custom path targets, consider appending PathElement buffers or creating custom maintenance dispatch entities.
- Maintenance actions are applied in MaintenanceJob — they mutate components such as NetCondition, LaneCondition, Damaged/Destroyed, Park. If you modify these components elsewhere, be mindful of job ordering and dependencies.
- Debugging tips:
- Inspect components: MaintenanceVehicle, MaintenanceRequest, MaintenanceConsumer, NetCondition, LaneCondition, Park.
- Watch service dispatch buffers on vehicles (ServiceDispatch) to see selected requests.
- The system uses an action queue (NativeQueue
If you want, I can also produce a compact class diagram of main components involved (MaintenanceVehicle, MaintenanceRequest, MaintenanceConsumer, NetCondition, LaneCondition, PathElement/PathOwner), or provide an example of programmatically creating a maintenance request entity that the system will pick up.