Skip to content

Game.City.CityUtils

Assembly: Assembly-CSharp
Namespace: Game.City

Type: public static class

Base: (static utility class — no instance/base type)

Summary:
CityUtils is a small helper/utility class used by the game to read/apply city options and city modifiers and to compute workplace capacity for city service buildings. It contains pure/static helpers that operate on City-related bitmasks, DynamicBuffer entries, and several ECS lookups to compute workplace maxima taking installed upgrades and school student counts into account.


Fields

  • None
    This type declares no fields.

Properties

  • None
    This type declares no properties.

Constructors

  • None (static utility class)
    There is no instance constructor. No static constructor is declared.

Methods

  • public static bool CheckOption(City city, CityOption option)
    Returns true if the given City has the specified option enabled. It checks city.m_OptionMask using (city.m_OptionMask & (1 << (int)option)) != 0. Use this to quickly test a city-level option bit.

Notes: - Safe to call with any City value; relies on City.m_OptionMask bitmask. - Equivalent to HasOption when you only have CityOptionData vs City.

  • public static void ApplyModifier(ref float value, DynamicBuffer<CityModifier> modifiers, CityModifierType type)
    Applies a modifier specified by type from the supplied DynamicBuffer to the provided value (passed by ref). The modifier is a float2 delta where:
  • delta.x is an additive offset applied first (value += delta.x)
  • delta.y is a multiplicative delta applied second (value += value * delta.y)

Behavior: - If modifiers.Length <= (int)type, no change is made. - The method modifies the supplied value in place.

Example behavior: - If value = 100, delta = (10, 0.1) -> value becomes 100 + 10 = 110, then 110 + 110 * 0.1 = 121.

Notes: - Ordering matters: additive applied before multiplicative. - Use when applying city-wide modifiers (tax, demand, etc.) stored in buffers.

  • public static float2 GetModifier(DynamicBuffer<CityModifier> modifiers, CityModifierType type)
    Returns the float2 delta for the specified modifier type, or default(float2) (0,0) if the buffer does not contain that index. Useful to read a modifier without applying it directly.

  • public static bool HasOption(CityOptionData optionData, CityOption option)
    Checks whether the provided CityOptionData has a given option bit set. Similar to CheckOption but operates on CityOptionData.m_OptionMask.

Notes: - Both this and CheckOption use a 1 << (int)option bit test on an uint mask.

  • public static int GetCityServiceWorkplaceMaxWorkers(Entity ownerEntity, ref ComponentLookup<PrefabRef> prefabRefs, ref BufferLookup<InstalledUpgrade> installedUpgrades, ref ComponentLookup<Deleted> deleteds, ref ComponentLookup<WorkplaceData> workplaceDatas, ref ComponentLookup<SchoolData> schoolDatas, ref BufferLookup<Student> studentBufs)
    Computes and returns the maximum number of workers for a city service workplace instance (ownerEntity). The computation accounts for:
  • The base workplace data from the prefab referenced by the owner's PrefabRef.
  • Installed upgrades on the instance (each upgrade may add minimum and maximum worker counts).
  • The Deleted component: if the owner entity is marked Deleted the result is 0.
  • If the prefab is a school (SchoolData present) the returned max worker count is adjusted based on current student load (studentBufs length vs school student capacity) using Mathf.Lerp: result is max(minimumAllowed, Lerp(0, result, studentCount / studentCapacity)).

Detailed logic: 1. If deleteds.HasComponent(ownerEntity) => return 0. 2. Resolve the prefab entity: entity = prefabRefs[ownerEntity]; if that prefab entity does not have WorkplaceData => return 0. 3. Start result = workplaceDatas[entity].m_MaxWorkers. 4. If no installedUpgrades buffer exists on owner, return the current result. 5. num = (workplaceDatas[entity].m_MinimumWorkersLimit == 0) ? result : workplaceDatas[entity].m_MinimumWorkersLimit - This num is the running minimum allowed number of workers (base or explicitly configured minimum). 6. For each InstalledUpgrade in installedUpgrades[ownerEntity]: - If prefabRefs.HasComponent(upgradeEntity) && !deleteds.HasComponent(upgradeEntity): - Resolve upgrade prefab entity2 = prefabRefs[item.m_Upgrade] - If workplaceDatas.HasComponent(entity2), then add workplaceDatas[entity2].m_MinimumWorkersLimit to num and workplaceDatas[entity2].m_MaxWorkers to result. 7. If the base prefab has SchoolData: - studentCapacity = schoolDatas[entity].m_StudentCapacity - length = studentBufs[ownerEntity].Length (current students) - result = math.max(num, (int)Mathf.Lerp(0f, result, 1f * length / (float)studentCapacity)) 8. Return result.

Notes and pitfalls: - The method expects properly populated ComponentLookup/BufferLookup objects (typically created via System.Stateful lookups in a SystemBase/System). - PrefabRef lookup must exist for the ownerEntity and for each installed upgrade to include their workplace data. - Ensure you call BufferLookup.HasBuffer/ComponentLookup.HasComponent checks where appropriate (the method itself calls HasBuffer and HasComponent internally in places). - The school capacity adjustment uses Mathf.Lerp with integer cast; if studentCapacity is 0 this will be a divide-by-zero—however in normal data school studentCapacity should be > 0. Still, callers should ensure valid data. - This method uses math.max to ensure the returned number is at least the computed minimum limit.

Usage Example

// Example: checking options and applying modifiers inside a SystemBase
protected override void OnUpdate()
{
    // Example: Check city option
    City city = ...; // obtain City struct (from some singleton/context)
    bool enabled = CityUtils.CheckOption(city, CityOption.SomeOption);

    // Example: apply a city modifier stored in a DynamicBuffer<CityModifier>
    Entity cityEntity = ...;
    DynamicBuffer<CityModifier> modifiers = SystemAPI.GetBuffer<CityModifier>(cityEntity);
    float taxRate = 10f;
    CityUtils.ApplyModifier(ref taxRate, modifiers, CityModifierType.TaxRate);
    // taxRate is now changed according to additive and multiplicative deltas.

    // Example: compute service workplace capacity inside a system using lookups
    var prefabRefs = GetComponentLookup<PrefabRef>(true);
    var installedUpgrades = GetBufferLookup<InstalledUpgrade>(true);
    var deleteds = GetComponentLookup<Deleted>(true);
    var workplaceDatas = GetComponentLookup<WorkplaceData>(true);
    var schoolDatas = GetComponentLookup<SchoolData>(true);
    var studentBufs = GetBufferLookup<Student>(true);

    Entity ownerEntity = ...; // building instance
    int maxWorkers = CityUtils.GetCityServiceWorkplaceMaxWorkers(ownerEntity,
        ref prefabRefs, ref installedUpgrades, ref deleteds, ref workplaceDatas, ref schoolDatas, ref studentBufs);
}

Additional tips: - Use CheckOption / HasOption to quickly read option bitmasks; these are simple bit tests and very cheap. - When working with DynamicBuffer, always check modifiers.Length against (int)type before indexing (ApplyModifier/GetModifier already handle that). - When calling GetCityServiceWorkplaceMaxWorkers, call it from a context where the provided lookups are valid and up-to-date (within a system update where lookups have been created and queried correctly).