Game.Simulation.LeisureSystem
Assembly:
Namespace: Game.Simulation
Type: class
Base: GameSystemBase
Summary:
LeisureSystem is a game simulation system that manages citizens' leisure behavior. It selects leisure types for citizens (based on wealth, age, weather, time, and tourist status), enqueues pathfinding requests to leisure locations, handles consumption of leisure-related resources and service availability, and removes Leisure state when finished. The system runs as a scheduled job pipeline: a parallel chunk job (LeisureJob) that decides leisure targets and enqueues pathfind/setup items, and a single-threaded job (SpendLeisurejob) that processes actual resource consumption and money transfers. It also integrates with other systems (PathfindSetupSystem, ResourceSystem, TimeSystem, ClimateSystem, AddMeetingSystem, EndFrameBarrier) via queues and command buffers.
Fields
-
private static readonly int kLeisureConsumeAmount
Constant consumption amount used when a citizen spends money/resources on a leisure visit (value = 2). -
private SimulationSystem m_SimulationSystem
Reference to the global SimulationSystem used to read the current simulation frame index and other simulation-level info. -
private EndFrameBarrier m_EndFrameBarrier
Barrier system used to create an EntityCommandBuffer. The LeisureJob enqueues changes through a parallel command buffer created from this barrier. -
private PathfindSetupSystem m_PathFindSetupSystem
Reference to the PathfindSetupSystem; the system enqueues pathfind setup requests via this system's queue. -
private TimeSystem m_TimeSystem
Reference to TimeSystem used to read time-of-day information needed for scheduling and path choices. -
private ResourceSystem m_ResourceSystem
Reference to ResourceSystem used for accessing resource prefabs and registering readers/writers. -
private ClimateSystem m_ClimateSystem
Reference to ClimateSystem; weather and temperature influence leisure selection weights for outdoor leisure types. -
private AddMeetingSystem m_AddMeetingSystem
Reference used to add meeting requests for leisure types that require meetings (e.g., Sightseeing, Attractions, Travel). -
private EntityQuery m_LeisureQuery
EntityQuery that matches citizens currently in Leisure state (and other relevant component constraints). The system requires this query for update. -
private EntityQuery m_EconomyParameterQuery
Query used to fetch EconomyParameterData singleton. -
private EntityQuery m_LeisureParameterQuery
Query used to fetch LeisureParametersData singleton. -
private EntityQuery m_ResidentPrefabQuery
Query that collects resident prefab archetype chunks needed when selecting resident prefabs for pathfind generation. -
private EntityQuery m_TimeDataQuery
Query used to fetch TimeData singleton. -
private EntityQuery m_PopulationQuery
Query to access Population singleton and population entity. -
private ComponentTypeSet m_PathfindTypes
ComponentTypeSet containing PathInformation and PathElement used when adding pathfind components to a citizen. -
private NativeQueue<LeisureEvent> m_LeisureQueue
NativeQueue used to accumulate LeisureEvent items (citizen + provider) from the parallel LeisureJob and consumed later by SpendLeisurejob. Allocated with Persistent lifetime. -
private TypeHandle __TypeHandle
Generated struct holding component & lookup handles used to schedule jobs (set in OnCreateForCompiler / __AssignHandles).
Properties
- (no publicly exposed properties)
Constructors
public LeisureSystem()
Default constructor. System initialization and actual setup happen in OnCreate / OnCreateForCompiler.
Methods
-
public override int GetUpdateInterval(SystemUpdatePhase phase)
Returns the interval (in simulation frames) at which the system should run. This system runs every 16 simulation frames (returns 16). -
protected override void OnCreate()
Initializes references to other systems, entity queries, pathfind type set, and creates the m_LeisureQueue. Calls RequireForUpdate for queries that must exist for the system to run. Called when the system is created. -
protected override void OnDestroy()
Disposes the m_LeisureQueue and performs base cleanup. -
protected override void OnUpdate()
Main scheduling method that: - Computes the update frame index with SimulationUtils.GetUpdateFrameWithInterval.
- Gathers runtime data (weather, temperature, economy parameters, time data, population).
- Schedules LeisureJob as a parallel IJobChunk over the m_LeisureQuery. LeisureJob:
- Selects leisure type for citizens without a current purpose (FindLeisure).
- Adds PathInformation / PathElement components and enqueues SetupQueueItem to m_PathfindQueue to find leisure destinations.
- If a leisure provider is already targeted or at current building, tries to SpendLeisure (enqueue LeisureEvent) or remove Leisure component when finished.
- Handles meeting-type leisure (Attractions, Sightseeing, Travel) by enqueueing AddMeeting requests.
- Adds job handle dependencies to m_EndFrameBarrier and m_PathFindSetupSystem.
- Schedules SpendLeisurejob (IJob) that dequeues m_LeisureQueue and actually performs resource and money transfers, adjusting ServiceAvailable, applying price multipliers, and consuming provider resources; notifies resource system that it reads prefabs.
-
Updates base.Dependency with scheduled jobs.
-
public static void AddToTempList(NativeList<LeisureProviderData> tempProviderList, LeisureProviderData providerToAdd)
Helper to merge multiple LeisureProviderData entries into a temporary list: if the same leisure type and resource combination already exists in the list, it aggregates the efficiency instead of adding a duplicate. -
private void __AssignQueries(ref SystemState state)
Compiler helper used in generated code path. In this version it creates and disposes an EntityQueryBuilder; exists to satisfy generated initialization paths. -
protected override void OnCreateForCompiler()
Compiler-time setup invoked to assign component/lookup handles via __TypeHandle.__AssignHandles and to prepare queries.
Nested job types (key behavior summary):
- SpendLeisurejob : IJob
- Dequeues LeisureEvent items (citizen, provider) produced by LeisureJob.
- Validates that the citizen and provider still exist and have expected components (HouseholdMember, PrefabRef, IndustrialProcess, Resources buffers).
- If provider is a service company, adjusts service availability and service price multipliers using ServiceCompanyData and ServiceAvailable (and updates mean priority).
- Checks resource availability at the provider, consumes a fixed amount (kLeisureConsumeAmount) of provider resource and transfers money from household to provider according to market prices (using EconomyUtils and ResourcePrefabs).
-
Skips processing if service is unavailable or provider lacks resources.
-
LeisureJob : IJobChunk
- Runs per-chunk over citizens that have a Leisure component.
- For each citizen it:
- If citizen already has a target/provider (current building or property renter), tries to SpendLeisure immediately (enqueuing events) and removes Leisure when completed or when provider becomes invalid or exhausted.
- Otherwise, if citizen already has a path planned and destination is a candidate leisure provider, sets Target/TripNeeded and the Leisure target.
- If citizen has no current Purpose, selects a leisure type with SelectLeisureType (weights by age, wealth, weather, temperature, and tourist chance), then either:
- Enqueues a meeting (for Attractions, Sightseeing, Travel) to AddMeetingSystem,
- Or sets up a pathfinding request to find a leisure target using PathfindSetupSystem (builds PathfindParameters taking account of walking/car, parking, authorizations, and supported activities).
- Uses RandomSeed per chunk for selection randomness and safety.
Private helper methods inside LeisureJob (summarized):
-
SpendLeisure(int index, Entity entity, ref Citizen citizen, ref Leisure leisure, Entity providerEntity, LeisureProviderData provider)
Validates provider availability (inactive buildings, serviceAvailability, resource availability), increments citizen.m_LeisureCounter by provider.m_Efficiency if valid and enqueues a LeisureEvent, removes Leisure component when a citizen is done (counter > 250), when leisure window expired, or when provider invalid. -
GetWeight(LeisureType type, int wealth, CitizenAge age) : float
Returns a weight value for a specific leisure type given a citizen's wealth and age. Weights differ by leisure type and factor in weather and temperature for outdoor types. -
SelectLeisureType(Entity household, bool tourist, Citizen citizenData, ref Random random) : LeisureType
Chooses a LeisureType for a citizen using weighted random sampling based on household spendable money (household wealth), citizen age, and tourist status. For tourists, a ~30% chance to select Attractions. If weight sampling fails, logs a warning and returns LeisureType.Count. -
FindLeisure(int chunkIndex, Entity citizen, Entity household, Citizen citizenData, ref Random random, bool tourist)
Orchestrates leisure selection and pathfind enqueueing: chooses leisure type, if meeting-type enqueues AddMeeting; otherwise sets up pathfind parameters (including walking speed, weights, pedestrian/vehicle methods, parking details if citizen has a car) and enqueues a SetupQueueItem to m_PathfindQueue.
Usage Example
// Example: add a Leisure component to a citizen to start leisure behavior.
// This will cause LeisureSystem to consider the citizen during its next scheduled update.
var em = World.DefaultGameObjectInjectionWorld.EntityManager;
Entity citizenEntity = /* an existing citizen entity */;
var leisure = new Leisure
{
m_TargetAgent = Entity.Null,
m_LastPossibleFrame = (uint)(simulationSystem.frameIndex + 6000) // expiration in future frames
};
em.AddComponentData(citizenEntity, leisure);