# Progression

**URL:** https://heroiclabs.com/docs/hiro/unity/progression/
**Keywords:** progression, hiro
**Categories:** hiro, unity, progression

---


# Progression

Read more about the Progression system in Hiro [here](../../concepts/progression/).

## Initializing the progression system

The progression system relies on the [Nakama System](../getting-started/nakama-system) and an `ILogger`, both must be passed in as dependencies via the constructor.

```csharp
var progressionSystem = new ProgressionSystem(logger, nakamaSystem);
systems.Add(progressionSystem);
```

## Subscribing to changes in the progression system

You can listen for changes in the progression system so that you can respond appropriately, such as updating the UI, by implementing the `IObserver` pattern, or use the `SystemObserver<T>` type which handles it for you.

```csharp
var disposer = SystemObserver<ProgressionSystem>.Create(progressionSystem, system => {
    Instance.Logger.Info($"System updated.");

    // Update UI elements etc as necessary here...
});
```

## Refreshing the progression system

To ensure the progression system has the latest information from Nakama you can refresh it.

```csharp
await progressionSystem.RefreshAsync();
```

## Get progressions for the user

You can get all progressions for the current user including their current status and a dependency tree containing any unmet preconditions.

```csharp
var progressions = await progressionSystem.GetProgressionsAsync();

foreach (var kvp in progressions)
{
    Debug.Log($"Progression {kvp.Key}");
    Debug.Log($"Is Unlocked? {kvp.Value.Unlocked}");

    if (!kvp.Value.Unlocked)
    {
        Debug.Log("Unmet preconditions:");
        PrintUnmetPreconditions(kvp.Value.UnmetPreconditions);
    }
}

async void PrintUnmetPreconditions(IProgressionPreconditionsBlock block)
{
    var progressions = await progressionSystem.GetProgressionsAsync();

    foreach (var kvp in progressions)
    {
        Debug.Log($"Progression {kvp.Key}");
        Debug.Log($"Is Unlocked? {kvp.Value.Unlocked}");

        if (!kvp.Value.Unlocked)
        {
            Debug.Log("Unmet preconditions:");
            PrintUnmetPreconditions(kvp.Value.UnmetPreconditions);
        }
    }

    void PrintUnmetPreconditions(IProgressionPreconditionsBlock block)
    {
        Debug.Log($"Block Operator: {block.Operator}");

        if (block.Direct != null)
        {
            Debug.Log("Direct");
            Debug.Log($"Progressions: {string.Join(", ", block.Direct.Progressions)}");
            Debug.Log($"Achievements: {string.Join(", ", block.Direct.Achievements)}");
            Debug.Log($"Counts: {string.Join(", ", block.Direct.Counts.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"ItemsMin: {string.Join(", ", block.Direct.ItemsMin.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"ItemsMax: {string.Join(", ", block.Direct.ItemsMax.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"StatsMin: {string.Join(", ", block.Direct.StatsMin.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"StatsMax: {string.Join(", ", block.Direct.StatsMax.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"EnergyMin: {string.Join(", ", block.Direct.EnergyMin.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"EnergyMax: {string.Join(", ", block.Direct.EnergyMax.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"CurrencyMin: {string.Join(", ", block.Direct.CurrencyMin.Select(kv => $"{kv.Key}: {kv.Value}"))}");
            Debug.Log($"CurrencyMax: {string.Join(", ", block.Direct.CurrencyMax.Select(kv => $"{kv.Key}: {kv.Value}"))}");
        }

        if (block.Nested != null)
        {
            Debug.Log("Nested");
            PrintUnmetPreconditions(block.Nested);
        }
    }
}
```

## Update the counters of a progression

You can update one or more counters towards a progression for the user.

```csharp
var progressions = await progressionSystem.UpdateProgressionAsync("<progressionId>", new Dictionary<string, long>
{
    { "rank", 2 },
    { "xp", 5 }
});
```

## Purchase a progression

You can purchase the unlock of a specified progression for the user.

```csharp
var progressions = await progressionSystem.PurchaseProgressionAsync("<progressionId>");
```
