# Hiro Teams Sample Project

**URL:** https://heroiclabs.com/docs/sample-projects/unity/hiro-teams/
**Summary:** Team management sample project for Unity games
**Keywords:** hiro teams, nakama authentication, unity sdk, hiro teams coordinator, teams system, systems architecture, hiro economy, device-based login
**Categories:** unity, sample-projects, hiro-teams

---


## Code overview

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

### Coordinator (`HiroTeamsCoordinator.cs`)

Extends `HiroCoordinator` to configure Nakama, register the `TeamsSystem` and `EconomySystem`, and expose a reusable authorizer for device-based login.

```csharp
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(HiroTeamsCoordinator), monitor, storage, logger);
    systems.Add(nakamaSystem);
    var teamsSystem = new TeamsSystem(logger, nakamaSystem);
    systems.Add(teamsSystem);
    var economySystem = new EconomySystem(logger, nakamaSystem, EconomyStoreType.Unspecified);
    systems.Add(economySystem);

    return Task.FromResult(systems);
}
```

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

---

### Controller (`HiroTeamsController.cs`)

Bridges the UI and the Hiro Teams API. Handles authentication events, maintains the team list and member cache, and exposes async methods for every team operation.

#### Team discovery

**Refresh teams**

Refresh the `TeamsSystem`, then populate the local team list.

```csharp
public async Task<int?> RefreshTeams(int tabIndex)
{
    Teams.Clear();

    await _teamsSystem.RefreshAsync();

    SelectedTeam = null;
    _selectedTeamId = string.Empty;
    return null;
}
```

**Search teams**

Filter teams server-side by name, language tag, and minimum activity.

```csharp
public async Task SearchTeams(
    string teamName, string language,
    int minActivity, bool? openFilter = null)
{
    Teams.Clear();

    var results = await _teamsSystem.SearchTeamsAsync(
        name: teamName ?? "",
        langTag: language ?? "",
        limit: teamEntriesLimit,
        minActivity: minActivity
    );

    SelectedTeam = null;
    _selectedTeamId = string.Empty;
    SelectedTeamMembers.Clear();
}
```

#### Team lifecycle

**Create a team**

Serialize avatar data as JSON and pass it alongside the team name, description, open/closed flag, and language tag.

```csharp
public async Task CreateTeam(
    string teamName, string description,
    bool isOpen, int backgroundIndex,
    int iconIndex, string language = "en")
{
    var avatarDataJson = JsonUtility.ToJson(new AvatarData
    {
        backgroundIndex = backgroundIndex,
        iconIndex = iconIndex
    });

    await _teamsSystem.CreateTeamAsync(
        teamName,
        description,
        isOpen,
        avatarDataJson,
        language,
        "{}"
    );
}
```

**Join, leave, and delete**

Single-call wrappers around the `TeamsSystem` for joining an open team, leaving the current team, and deleting a team (Super Admin only).

#### Member management

**Role-based actions**

Promote, demote, kick, and ban members through the `TeamsSystem`. Handle join requests by approving or rejecting them. See [Roles and permissions](../../../hiro/concepts/teams/#roles-and-permissions) for more nformation on team roles and permissable actions.

```csharp
public async Task PromoteUser(string userId)
{
    if (SelectedTeam == null) return;
    await _teamsSystem.PromoteUsersAsync(SelectedTeam.Id, new[] { userId });
}

public async Task AcceptJoinRequest(string userId)
{
    if (SelectedTeam == null) return;
    await _teamsSystem.ApproveJoinRequestAsync(SelectedTeam.Id, userId);
}
```

#### Mailbox

**List and claim rewards**

Fetch claimable mailbox entries from the `TeamsSystem` and claim them individually or all at once.

```csharp
public async Task<List<IRewardMailboxEntry>>
    GetMailboxEntriesAsync()
{
    MailboxEntries.Clear();

    if (_teamsSystem?.Team == null) return MailboxEntries;

    var mailbox = await _teamsSystem.ListMailboxAsync();
    foreach (var entry in mailbox.Entries)
    {
        if (entry.CanClaim)
        {
            MailboxEntries.Add(entry);
        }
    }

    return MailboxEntries;
}
```

API reference: [Teams](../../../hiro/unity/teams/)

---

### Views

**TeamsView**

Main screen handling two top-level tabs (All Teams / My Team), the team list, selected team detail panel, team-level tabs (Members, Gifts, Chat, Mailbox, About), search and create modals, a debug modal for adjusting team stats, and error handling. Non-members see a preview panel with public stats; members see the full tabbed interface with role-appropriate action buttons.

**TeamView**

Single team list entry showing the avatar, team name, and member count.

**TeamMemberView**

Per-member row in the members list. Displays username and role, then conditionally shows accept/decline, promote/demote, kick, and ban buttons based on the viewer's role relative to the listed member.
