# Create Custom Systems

**URL:** https://heroiclabs.com/docs/hiro/unity/getting-started/custom-systems/
**Summary:** Learn how to create custom systems in Hiro.
**Keywords:** create custom systems, hiro
**Categories:** hiro, unity, custom-systems

---


# Create Custom Systems

Along with facilitating the implementation of powerful Nakama-based features into your game, Hiro can also be used to help you structure your own game systems and logic.

This page demonstrate two different custom systems to showcase how you can use this functionality: the first example makes use of an existing Hiro system while the second is not tied to existing systems at all.

## With existing Hiro systems

The first example will set the player's initial stats if this is their first time installing the game.

```csharp
public struct PlayerStats
{
    public int Health;
    public int Attack;
    public int Strength;
    public int Defense;
}

public class FirstTimePlayerSystem : IInitializeSystem, IUserSystem
{
    public string Name => nameof(FirstTimePlayerSystem);
    public bool IsInitialized { get; private set; }

    private NakamaSystem _nakamaSystem;

    public FirstTimePlayerSystem(NakamaSystem nakamaSystem)
    {
        _nakamaSystem = nakamaSystem;
    }

    public async Task InitializeAsync()
    {
        const string collection = "Stats";
        var playerInitObject = await _nakamaSystem.ReadStorageObjectAsync(collection, _nakamaSystem.UserId, _nakamaSystem.UserId);

        if (playerInitObject == null)
        {
            var initialStats = new PlayerStats
            {
                Health = 10,
                Attack = 1,
                Strength = 1,
                Defense = 1
            };

            var writeObject = new WriteStorageObject
            {
                Collection = collection,
                Key = _nakamaSystem.UserId,
                PermissionRead = 2,
                PermissionWrite = 1
            };

            var acks = await _nakamaSystem.WriteStorageObjectsAsync(new [] { writeObject });
        }

        IsInitialized = true;
    }
}
```

## Without existing Hiro systems

The second example makes use of Hiro's deterministic startup to ensure that it runs after another system has been initialized and then bootstraps the gameplay logic.

```csharp
public class GameBootstrapSystem : IInitializeSystem
{
    public string Name => nameof(FirstTimePlayerSystem);
    public bool IsInitialized { get; private set; }

    private NakamaSystem _nakamaSystem;

    public GameBootstrapSystem(NakamaSystem nakamaSystem)
    {
        _nakamaSystem = nakamaSystem;
    }

    public async Task InitializeAsync()
    {
        if (!_nakamaSystem.IsInitialized)
        {
            return Task.FromException(new InvalidOperationException("NakamaSystem is not initialized"));
        }

        GameManager.Instance.Initialize(_nakamaSystem);
        GameManager.Instance.StartGame();
    }
}
```

### Handling failures during initialization

While the order of initialization is deterministic, it is important to ensure that systems you are dependent on have initialized successfully.

In the above scenario:

1. The `IsInitialized` property of the `NakamaSystem` is checked to ensure that the system was fully initialized before continuing.
2. If not, the `InitializeAsync` call returns with an `Exception` wrapped in a `Task`.
3. This is then handled by the `Systems` object which will call the system's `InitializeFailedAsync` method.

You can handle this two ways:

1. If the initialization failure of this system is critical to your game, you can re-throw the exception from within `InitializeFailedAsync`.

This causes the main `Systems` object to halt the initialization flow, stopping any further systems from being initialized.

```csharp
public async Task InitializeFailedAsync(ILogger logger, Exception e)
{
    logger.Error($"GameBootstrapSystem failed to initialize, halting further initialization.\n{e.Message}");

    // Re-throw the exception, causing the Systems object to halt further initialization
    return Task.FromException(e);
}
```

2. You can choose to allow initialization of further systems to continue by returning a completed task.

```csharp
public async Task InitializeFailedAsync(ILogger logger, Exception e)
{
    logger.Error($"GameBootstrapSystem failed to initialize, continuing initialization of other systems.\n{e.Message}");

    // Return a completed task to allow further systems to be initialized
    return Task.CompletedTask;
}
```
