# Hiro Achievements Sample Project

**URL:** https://heroiclabs.com/docs/sample-projects/unity/hiro-achievements/
**Summary:** Achievements, quests, and reward-claiming sample project for Unity games
**Keywords:** hiro achievements, unity, nakama, achievements, progression, quests, reward claiming, hiro achievements coordinator, hiro coordinator, device-based authentication
**Categories:** unity, sample-projects, hiro-achievements

---


## Code overview

The project uses Hiro’s systems-based architecture, which provides an opinionated structure for building games with pre-configured systems.

### Coordinator (`HiroAchievementsCoordinator.cs`)

Extends `HiroCoordinator` to configure Nakama, register Hiro systems, and expose a reusable authorizer for device-based login.

```csharp
// Create and register Hiro systems
protected override Task<Systems> CreateSystemsAsync()
{
    var logger = new Hiro.Unity.Logger();
    var monitor = NetworkMonitor.Default;
    var client = localHost
        ? new Client("http", "127.0.0.1", 7350, "defaultkey")
        : new Client(scheme, host, port, serverKey);

    var nakamaSystem = new NakamaSystem(logger, client, NakamaAuthorizerFunc());
    var storage = MemoryStorage.Default;

    var systems = new Systems(nameof(HiroAchievementsCoordinator), monitor, storage, logger);
    systems.Add(nakamaSystem);
    systems.Add(new InventorySystem(logger, nakamaSystem));
    systems.Add(new EconomySystem(logger, nakamaSystem, EconomyStoreType.Unspecified));
    systems.Add(new AchievementsSystem(logger, nakamaSystem));
    return Task.FromResult(systems);
}
```

API reference: [Hiro Initialization](../../../hiro/unity/getting-started/nakama-system)

### Controller (`AchievementsController.cs`)

Bridges the UI and Hiro Achievements API. Handles authentication events, category filtering, and orchestrates updates across achievements, sub-achievements, and rewards.

**Load achievements**

Refresh the Hiro achievements system, clear existing caches, and repopulate the controller’s local lists with all achievements and repeatable achievements, including locked items. 

```csharp
public async Task LoadAchievements()
{
    AllAchievements.Clear();
    RepeatAchievements.Clear();

    await _achievementsSystem.RefreshAsync();

    // Get all achievements (including locked ones)
    var achievements = _achievementsSystem.GetAchievements();
    AllAchievements.AddRange(achievements);

    // Get repeatable achievements (including locked ones)
    var repeatAchievements = _achievementsSystem.GetRepeatAchievements();
    RepeatAchievements.AddRange(repeatAchievements);

    Debug.Log($"Loaded {AllAchievements.Count} achievements, {RepeatAchievements.Count} repeatable");
}
```

**Update achievements progress**

Validate the achievement ID and progress. Send a progress update to Hiro Achievements, then refresh local achievement and economy data so lists reflect the latest state.

```csharp
public async Task UpdateAchievementProgress(string achievementId, long progress)
{
    if (string.IsNullOrEmpty(achievementId))
        throw new Exception("Invalid achievement ID.");

    if (progress <= 0)
        throw new Exception("Progress must be greater than 0.");

    var updates = new Dictionary<string, long>
    {
        { achievementId, progress }
    };

    await _achievementsSystem.UpdateAchievementsAsync(updates);
    await RefreshAchievements();
}
```

**Claim rewards and refresh the wallet**

Claim the reward for the selected achievement or sub‑achievement. If a sub‑achievement is selected, claim its reward and return. Otherwise, verify a main achievement is selected and claim its reward. Use the claimTotal flag to claim the total reward.

```csharp
// Claim rewards for the selected achievement (or sub-achievement) and sync the wallet UI
public async Task ClaimAchievementReward(bool claimTotal = true)
{
    if (_selectedSubAchievement != null)
    {
        await ClaimAchievementReward(_selectedSubAchievement.Id, claimTotal);
        return;
    }

    if (_selectedAchievement == null)
        throw new Exception("No achievement selected.");

    await ClaimAchievementReward(_selectedAchievement.Id, claimTotal);
}
```

### Achievements view (`AchievementsView.cs`)

Connect the UI Toolkit document to the controller logic. Handle tab filters for dailies, quests, and achievements; populate the achievements list; show prerequisites and rewards; and wire action buttons for progress and claim. Observe the Hiro wallet so currency changes appear immediately after a claim.

### Sub-achievement view (`SubAchievementItemView.cs`)

Format sub‑achievement objectives in the details panel. Show per‑objective progress, reward text, and status badges; send selection events to the controller for targeted updates.

### Prerequisite helpers (`PrerequisiteDisplayHelper.cs`, `AchievementProgressHelper.cs`)

Use utility classes to centralize progress calculations, lock‑state checks, and formatted prerequisite messages, keeping list items and detail views consistent.