Skip to content

Game.UI.InGame.ProgressionUtils

Assembly:
Assembly-CSharp (Game) — typical runtime assembly for Cities: Skylines 2 game code.
Namespace:
Game.UI.InGame

Type:
static class

Base:
System.Object (static utility class)

Summary:
Utility helpers for working with unlock/progression requirements for prefabs (entities). Provides methods to collect transitive unlock requirements (into a NativeParallelHashMap) and to compute the required milestone index for unlocking a given entity by inspecting its UnlockRequirement buffer and related MilestoneData. These helpers interact with Unity.Entities (EntityManager, DynamicBuffer) and Unity.Collections (NativeParallelHashMap), and are intended to be used from game/mod code that queries prefab unlock relationships.


Fields

  • None
    This static utility class does not declare any instance or static fields.

Properties

  • None
    No properties are exposed by this static class.

Constructors

  • None
    This is a static class and has no public constructors. (If needed the runtime may generate a static constructor; none are declared in source.)

Methods

  • public static bool CollectSubRequirements(EntityManager entityManager, Entity prefab, NativeParallelHashMap<Entity, UnlockFlags> requiredPrefabs, UnlockFlags flags = UnlockFlags.RequireAll | UnlockFlags.RequireAny)
    Collects transitive unlock requirements for the specified prefab into the provided requiredPrefabs map.

  • Parameters:

    • entityManager: The EntityManager to query components and buffers from.
    • prefab: The prefab (Entity) whose unlock requirements will be walked.
    • requiredPrefabs: A caller-provided NativeParallelHashMap that will be populated with required prefabs (keys) and their aggregated UnlockFlags (values). The map is mutated by the method.
    • flags: Filter flags used early in the method to short-circuit visiting entries. Default is UnlockFlags.RequireAll | UnlockFlags.RequireAny.
  • Returns:

    • bool — The method returns true in the case where a direct self-referential unlock requirement with the RequireAll flag is found in the prefab's UnlockRequirement buffer. For typical usage the caller is primarily interested in the side-effect of requiredPrefabs being filled; the boolean return value indicates the presence of that specific condition.
  • Behavior and notes:

    • If prefab == Entity.Null, or the prefab is already present in requiredPrefabs with overlapping flags ((requiredPrefabs[prefab] & flags) != 0), the method returns false and does not traverse further.
    • The method uses EntityManager.TryGetBuffer(prefab, out DynamicBuffer) to read the UnlockRequirement buffer for the prefab. Each UnlockRequirement is expected to contain at least m_Prefab (the required prefab entity) and m_Flags (UnlockFlags).
    • If a UnlockRequirement references the same prefab (m_Prefab == prefab) and has RequireAll set, the method returns true.
    • For each other referenced prefab it:
    • Temporarily adds the current prefab to requiredPrefabs to mark traversal,
    • Recursively calls CollectSubRequirements for the referenced prefab with that requirement's flags,
    • If the recursive call returns true, the referenced prefab is added to requiredPrefabs (or its flags are ORed with existing flags),
    • Removes the temporary mark for the current prefab before continuing.
    • The method mutates requiredPrefabs and expects the caller to provide and eventually dispose of it. It does not allocate or dispose the map itself.
    • The function relies on UnlockRequirement and UnlockFlags definitions (not shown here). Typical flags are RequireAll and RequireAny which control how requirements are aggregated.
    • Be careful with recursion and large requirement graphs — although the code avoids revisiting already-marked prefabs via the requiredPrefabs check, deep graphs could still lead to recursion depth.
  • public static int GetRequiredMilestone(EntityManager entityManager, Entity entity)
    Compute the highest milestone index required to unlock the given entity based on transitive unlock requirements.

  • Parameters:

    • entityManager: The EntityManager used to query components.
    • entity: The prefab (Entity) whose required milestone is computed.
  • Returns:

    • int — The maximum milestone index (component MilestoneData.m_Index) among required prefabs that are marked with RequireAll. Returns 0 if no applicable requirements or milestone components are found.
  • Behavior and notes:

    • If the entity does not have an UnlockRequirement component buffer, the method returns 0.
    • The method constructs a NativeParallelHashMap with Allocator.TempJob, calls CollectSubRequirements to fill it, then iterates the map.
    • For each entry in the map, if the entry's flags have RequireAll set and the referenced prefab has a MilestoneData component, the method reads MilestoneData.m_Index and tracks the highest value found.
    • The temporary NativeParallelHashMap is disposed before the method returns.
    • This method provides a convenient single-call way to obtain an integer milestone requirement without requiring the caller to manage the map lifetime.

Usage Example

// Example: compute the milestone required to unlock a given prefab (entity).
// This code would run in a context that has access to an EntityManager (e.g., in a System or mod initialization).

EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
Entity myPrefab = /* obtain the prefab entity you want to check */;

// Get the required milestone index (0 if none)
int requiredMilestone = ProgressionUtils.GetRequiredMilestone(entityManager, myPrefab);
Debug.Log($"Required milestone index for prefab: {requiredMilestone}");

// Example: If you want to collect the transitive requirements yourself for further processing:
var requiredPrefabs = new NativeParallelHashMap<Entity, UnlockFlags>(16, Allocator.TempJob);
bool specialFlagDetected = ProgressionUtils.CollectSubRequirements(entityManager, myPrefab, requiredPrefabs);

// requiredPrefabs now contains the set of required prefabs and their combined UnlockFlags.
// Remember to dispose the NativeParallelHashMap when done:
requiredPrefabs.Dispose();

Additional notes and recommendations: - Always dispose any NativeParallelHashMap you allocate (the class methods assume the caller will manage disposal when requiredPrefabs is provided). - This utility reads DynamicBuffer and components like MilestoneData; ensure the entity passed is a valid prefab entity with those buffers/components where appropriate. - UnlockFlags semantics: typically RequireAll indicates a hard requirement (all such prefabs must be unlocked), while RequireAny indicates alternatives. GetRequiredMilestone only considers RequireAll entries when deciding the milestone index. - When calling CollectSubRequirements directly in parallel or Jobs, ensure thread-safety constraints for the provided NativeParallelHashMap and that you use the appropriate Allocator and job dependencies.