Skip to content

Game.Simulation.MilestoneSystem

Assembly: Game (runtime simulation assembly)
Namespace: Game.Simulation

Type: class

Base: GameSystemBase, IMilestoneSystem

Summary:
Manages city milestone progression. The system tracks current XP and milestone thresholds, determines when the next milestone is reached, emits milestone-related events (MilestoneReachedEvent and Unlock), and grants milestone rewards and loan limit increases to the City entity. It uses ECS queries to read MilestoneData, the MilestoneLevel singleton and XP, and uses a ModificationEndBarrier to create event entities safely at the end of a simulation step. The system exposes properties to read current/required XP and progress.


Fields

  • private int m_LastRequired
    Stores the XP threshold of the most recently achieved milestone (last required XP).

  • private int m_NextRequired
    Stores the XP threshold required for the next milestone.

  • private int m_Progress
    Current progress XP since last milestone (city XP minus last required).

  • private int m_NextMilestone
    Index of the next milestone (achievedMilestone + 1).

  • private CitySystem m_CitySystem
    Cached reference to the CitySystem used to read the city's XP and to obtain the City entity.

  • private ModificationEndBarrier m_ModificationEndBarrier
    Barrier system used to create event entities (command buffer) at the end of modifications.

  • private EntityArchetype m_UnlockEventArchetype
    Archetype for creating Unlock event entities (Event + Unlock components).

  • private EntityArchetype m_MilestoneReachedEventArchetype
    Archetype for creating MilestoneReachedEvent entities (Event + MilestoneReachedEvent components).

  • private EntityQuery m_MilestoneLevelGroup
    Query for the MilestoneLevel singleton (used to read and update achieved milestone index).

  • private EntityQuery m_XPGroup
    Query that requires the presence of XP components (used to ensure system updates when XP exists).

  • private EntityQuery m_MilestoneGroup
    Query for entities with MilestoneData (used to look up milestone definitions and rewards).

Properties

  • public int currentXP => m_Progress
    Current XP progress since last achieved milestone.

  • public int requiredXP => nextRequiredXP - math.max(0, lastRequiredXP)
    XP required to go from the last achieved milestone to the next milestone (handles lastRequiredXP being negative via max).

  • public int lastRequiredXP => m_LastRequired
    The XP threshold of the last achieved milestone.

  • public int nextRequiredXP => m_NextRequired
    The XP threshold for the next milestone.

  • public float progress => (float)m_Progress / (float)requiredXP
    Normalized progress (0..1) toward the next milestone.

  • public int nextMilestone => m_NextMilestone
    Index of the next milestone.

Constructors

  • public MilestoneSystem()
    Default constructor (no custom initialization beyond base).

Methods

  • protected override void OnCreate()
    Initializes the system: caches CitySystem and ModificationEndBarrier, creates archetypes for milestone events, sets up EntityQueries for MilestoneLevel, XP, and MilestoneData, and calls RequireForUpdate on those queries so the system only runs when relevant components exist.

  • protected override void OnUpdate()
    Core per-frame logic:

  • Reads the MilestoneLevel singleton to get the currently achieved milestone index.
  • Updates m_LastRequired by finding the milestone data for the achieved milestone (if any).
  • Checks if the next milestone exists and updates m_NextRequired.
  • If the city's XP (from CitySystem) is greater than or equal to m_NextRequired, increments the achieved milestone, writes back the singleton, and calls NextMilestone to emit events and apply rewards.
  • Updates m_Progress (city XP minus last required) and m_NextMilestone.

  • private void NextMilestone(int index)
    Called when a milestone is reached:

  • Creates a command buffer from m_ModificationEndBarrier.
  • Tries to find the MilestoneData for the given index via TryGetMilestone.
  • If found:
    • Creates a MilestoneReachedEvent entity and an Unlock event entity using the command buffer.
    • Immediately updates the City entity's PlayerMoney (adds milestone reward) and Creditworthiness (increases loan limit).
  • If not found:
    • Creates a MilestoneReachedEvent with Entity.Null for the milestone entity and logs a warning.

Note: event entities are created via the command buffer to be processed safely later in the frame.

  • private bool TryGetMilestone(int index, out Entity entity, out MilestoneData milestone)
    Looks up milestone data by index:
  • Reads all entities and MilestoneData components matched by m_MilestoneGroup into temporary NativeArrays (Allocator.TempJob).
  • Iterates them to find one where m_Index == index.
  • If found returns true and outputs the entity and data.
  • Ensures NativeArrays are disposed in a finally block.
  • Returns false and sets outputs to default if not found.

  • public void UnlockAllMilestones()
    Force-unlocks all remaining milestones:

  • Reads all MilestoneData and entities into temporary NativeArrays.
  • Reads the MilestoneLevel singleton and City PlayerMoney and Creditworthiness components.
  • From the current achieved milestone up through all milestone entries, creates Unlock event entities and:
    • Updates singleton.m_AchievedMilestone to the maximum index seen.
    • Adds each milestone's reward to PlayerMoney.
    • Adds each milestone's loan limit to Creditworthiness.m_Amount.
  • Disposes the temporary arrays and writes back the updated singleton and City component data.
  • Note: this method uses EntityManager.CreateEntity directly for Unlock events (immediate creation).

Usage Example

// Example: get the milestone system and force-unlock all milestones from a mod entry point
var world = World.DefaultGameObjectInjectionWorld;
var milestoneSystem = world.GetOrCreateSystemManaged<Game.Simulation.MilestoneSystem>();
if (milestoneSystem != null)
{
    // Query current progress
    float progressRatio = milestoneSystem.progress;
    int currentXP = milestoneSystem.currentXP;
    int needed = milestoneSystem.requiredXP;

    // Force unlock all (gives all rewards and loan increases)
    milestoneSystem.UnlockAllMilestones();
}

Notes and implementation details: - The system relies on MilestoneData entities being present in the world (m_MilestoneGroup). If a milestone index is missing, the system logs a warning when that milestone is reached. - Milestone events created: - Unlock (component) — created when a milestone is unlocked (other systems can consume to enable prefabs/features). - MilestoneReachedEvent — indicates a milestone index was reached (provides the milestone entity or Entity.Null). Both event entities are created so that other systems can respond in the same frame or at an end-of-frame processing stage. - Temporary allocations: TryGetMilestone and UnlockAllMilestones use ToEntityArray / ToComponentDataArray with Allocator.TempJob; arrays are disposed in finally blocks to avoid leaks. - The system updates the City entity's PlayerMoney and Creditworthiness directly; ensure those components exist and are used consistently by other systems.