Skip to content

Game.Simulation.UtilityFeeSystem

Assembly: Assembly-CSharp (game runtime assembly)
Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
UtilityFeeSystem is a simulation system that collects utility fees (electricity, water, sewage) from buildings that have renters. It schedules a parallel IJobChunk (SellUtilitiesJob) that iterates consumer buildings each update slice, computes sold utility amounts based on fulfilled consumption, deducts money from renter resources, and enqueues aggregated fee events to the central ServiceFeeSystem. The system runs in slices (128 updates per day) and integrates with the city/service fee systems to report income.


Fields

  • private const int kUpdatesPerDay = 128
    Describes the number of update slices per "day" used by the system. Used to compute the update interval and to pick the current update frame.

  • private SimulationSystem m_SimulationSystem
    Reference to the SimulationSystem (used to obtain frame index and timing info).

  • private CitySystem m_CitySystem
    Reference to the CitySystem, used to get the city Entity (m_City) for looking up service fees.

  • private ServiceFeeSystem m_ServiceFeeSystem
    Reference to the ServiceFeeSystem, used to obtain a FeeQueue writer and to register the job's dependency.

  • private EntityQuery m_ConsumerGroup
    EntityQuery selecting buildings with renters and either electricity or water consumers. Filters out Deleted and Temp entities.

  • private TypeHandle __TypeHandle
    Internal struct instance that caches ECS Type/Buffer handles (ComponentTypeHandle/BufferTypeHandle/BufferLookup) required by the SellUtilitiesJob. Populated during compiler-time setup.

Properties

  • (no public properties declared on UtilityFeeSystem itself)
    All interaction occurs via system lifecycle methods and the ServiceFeeSystem's fee queue.

Constructors

  • public UtilityFeeSystem()
    Default constructor. The system is initialized by the ECS/System framework; real initialization happens in OnCreate.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns the update interval for the system. This system updates every 128 frames/slices (kUpdatesPerDay). Used by the GameSystemBase scheduling to stagger updates.

  • [Preserve] protected override void OnCreate()
    Initializes references to other systems (SimulationSystem, CitySystem, ServiceFeeSystem) and constructs the EntityQuery m_ConsumerGroup which targets Building + Renter + UpdateFrame and either ElectricityConsumer or WaterConsumer, excluding Deleted and Temp entities. This sets up the query the job uses to find consumer buildings.

  • [Preserve] protected override void OnUpdate()
    Main scheduling method. Computes the current update frame via SimulationUtils.GetUpdateFrame(..., 128, 16), allocates and fills SellUtilitiesJob with:

  • buffer/component handles (via InternalCompilerInterface + cached __TypeHandle)
  • shared UpdateFrame handle
  • buffer lookups for Resources and ServiceFee
  • city entity and update frame index
  • fee queue parallel writer from ServiceFeeSystem
  • a RandomSeed It then schedules the job in parallel across m_ConsumerGroup with proper dependency chaining, and registers the fee queue writer with the ServiceFeeSystem.

  • protected override void OnCreateForCompiler()
    Compiler-time helper that assigns queries and TypeHandle handles. Called by the generated/compiled system bootstrap.

  • [MethodImpl(MethodImplOptions.AggressiveInlining)] private void __AssignQueries(ref SystemState state)
    Internal helper used during compiler-time initialization; currently creates (and disposes) an EntityQueryBuilder to force query assignment. (Generated helper; implementation is minimal here.)

Nested types (important behavior)

  • private struct SellUtilitiesJob : IJobChunk
    Burst-compiled job that runs per archetype chunk. Responsibilities:
  • Filters chunks by matching UpdateFrame shared component index to m_UpdateFrameIndex (so each building is processed only in its assigned slice).
  • Reads ElectricityConsumer and WaterConsumer components (if present) and Renter buffers.
  • Reads the city ServiceFee buffer to get per-resource fees.
  • Uses a RandomSeed (per-chunk) for randomized rounding when subtracting money.
  • For each entity in the chunk:
    • Builds a float3 of fulfilled consumption: (electricity, fresh water, sewage), normalized by 128.
    • Computes per-renter charge = sum(consumption * fee) / renterCount.
    • For each renter entry in the building, finds their Resources buffer and deducts money with EconomyUtils.AddResources(Resource.Money, -roundedCharge, buffer).
  • Aggregates totals across the chunk and enqueues fee events for Electricity, Water, and Sewage using the ServiceFeeSystem.FeeEvent queue (m_FeeQueue).
  • Uses BufferLookup.TryGetBuffer to access renter-owned resources buffers. Works in parallel with NativeQueue.ParallelWriter for aggregated reporting.

Important details: - Uses InternalCompilerInterface handles provided when scheduling. - Employs Burst and parallel execution; pay attention to thread-safety when modifying buffers (m_Resources is marked NativeDisableParallelForRestriction and used via BufferLookup). - Randomized rounding is applied with MathUtils.RoundToIntRandom to distribute fractional charges.

  • private struct TypeHandle
    Holds Component/Buffer/BufferLookup handles:
  • BufferTypeHandle (RO)
  • ComponentTypeHandle (RO)
  • ComponentTypeHandle (RO)
  • BufferLookup (RW)
  • BufferLookup (RO) Includes __AssignHandles(ref SystemState) to populate handles from the system state (called in OnCreateForCompiler).

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    // Resolve systems and build the required EntityQuery
    m_SimulationSystem = base.World.GetOrCreateSystemManaged<SimulationSystem>();
    m_CitySystem = base.World.GetOrCreateSystemManaged<CitySystem>();
    m_ServiceFeeSystem = base.World.GetOrCreateSystemManaged<ServiceFeeSystem>();

    m_ConsumerGroup = GetEntityQuery(new EntityQueryDesc
    {
        All = new ComponentType[] {
            ComponentType.ReadOnly<Building>(),
            ComponentType.ReadOnly<Renter>(),
            ComponentType.ReadOnly<UpdateFrame>()
        },
        Any = new ComponentType[] {
            ComponentType.ReadOnly<ElectricityConsumer>(),
            ComponentType.ReadOnly<WaterConsumer>()
        },
        None = new ComponentType[] {
            ComponentType.ReadOnly<Deleted>(),
            ComponentType.ReadOnly<Temp>()
        }
    });
}

Additional notes and tips for modders: - The system charges renters, not buildings directly. Renters must have a Resources buffer present for money deductions to succeed. - Fees are read from the city's ServiceFee buffer — changing city fees (ServiceFeeSystem) will affect amounts charged here. - Because the job runs in parallel and is Burst-compiled, avoid modifying game state outside the provided buffers/queues; use ServiceFeeSystem's queue for reporting aggregated income rather than trying to write into shared city resources directly. - If adding new consumer types or altering consumption fields, mirror the logic in SellUtilitiesJob: include proper ComponentTypeHandles, update the consumption -> fee math, and ensure fees are enqueued for the correct PlayerResource.