> For the complete documentation index, see [llms.txt](https://megacrush.gitbook.io/megacrush-unity-assets/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://megacrush.gitbook.io/megacrush-unity-assets/runtime-spawner/runtime-spawner-user-manual/getting-started/specials-telemetry-system/creating-a-custom-telemetry-provider.md).

# Creating a Custom Telemetry Provider

Once you’ve confirmed your **Special Encounter rules** respond correctly using the sample asset, you can connect your **real gameplay data** by creating your own telemetry provider.

The telemetry system is intentionally flexible - you can feed in *any data source* as long as it provides two values:

| Metric                | Description                                     | Typical Range    |
| --------------------- | ----------------------------------------------- | ---------------- |
| **Pressure**          | How intense or “busy” the game currently feels. | 0–1 (normalized) |
| **Average Player HP** | The team’s mean health percentage.              | 0–1 (normalized) |

There are two main ways to implement a provider:

an **Inspector-based ScriptableObject** (plug-and-play) or a **runtime C# provider** (for live data).

***

### Option A - ScriptableObject Provider (Inspector Setup)

Use this approach when you want a configurable, reusable asset that can read or proxy values from your systems.

#### 1. Create a subclass of `SpecialsTelemetryProvider`

```csharp
using UnityEngine;
using MegaCrush.Spawner;

[CreateAssetMenu(menuName = "Runtime Spawner/Specials Telemetry/Game Linked")]
public sealed class GameLinkedTelemetry : SpecialsTelemetryProvider
{
    public override bool TryGetPressure(out float value)
    {
        // Example: pull from your own difficulty or director service
        value = GameServices.Difficulty.CurrentPressure01;
        return true;
    }

    public override bool TryGetAveragePlayerHP(out float value)
    {
        value = GameServices.Players.GetAverageHealth01();
        return true;
    }
}
```

#### 2. Create the asset

In Unity:\
**Create → Runtime Spawner → Specials Telemetry → Game Linked**

#### 3. Assign it to the Manager

Select your **SpecialEncounterManager** and drag your new asset into the **Telemetry Provider** field.

That’s it - your manager will now query your game’s live values automatically every evaluation cycle.

***

#### Pros

* Editable and swappable via inspector or profiles.
* Works with Addressables or asset-based pipelines.
* Ideal for designers tuning different pacing profiles.

#### Cons

* Slightly more setup than a code-only provider.
* Requires script access to your global systems or singletons.

***

### Option B - Runtime Provider (Code Injection)

If your telemetry data already lives in runtime systems (e.g., `GameState`, `DifficultyManager`, `PlayerService`), you can implement the lightweight **ISpecialsTelemetry** interface and inject it directly.

#### 1. Implement the interface

```csharp
using MegaCrush.Spawner;

public sealed class RuntimeTelemetry : ISpecialsTelemetry
{
    private readonly DifficultyManager _difficulty;
    private readonly PlayerService _players;

    public RuntimeTelemetry(DifficultyManager difficulty, PlayerService players)
    {
        _difficulty = difficulty;
        _players = players;
    }

    public bool TryGetPressure(out float value)
    {
        value = _difficulty.PressureNormalized;  // 0..1
        return true;
    }

    public bool TryGetAveragePlayerHP(out float value)
    {
        value = _players.GetAverageHealth01();
        return true;
    }
}
```

#### 2. Inject it at runtime

```csharp
var manager = FindAnyObjectByType<SpecialEncounterManager>();
manager.SetTelemetryProvider(new RuntimeTelemetry(difficulty, players));
```

You can inject it right after initializing the Runtime Spawner or during your bootstrap sequence.

***

#### Pros

* No asset setup required.
* Works cleanly with dependency injection and services.
* Easy to test and mock.

#### Cons

* Not visible in the inspector.
* Requires code changes if you want to swap providers.

***

### Recommended Scales

Keep telemetry values **normalized between 0 and 1**.\
This keeps thresholds predictable across different rule sets:

| Value | Interpretation                           |
| ----- | ---------------------------------------- |
| 0.0   | Calm / no intensity / players near death |
| 0.5   | Normal tension / moderate health         |
| 1.0   | Extreme intensity / full health          |

Rules like

> *“Spawn a miniboss when Pressure ≥ 0.8 and AvgHP ≥ 0.5”*\
> will be easier to tune when all systems use a consistent scale.

***

### Advanced: Combining Providers

You can dynamically swap telemetry sources:

```csharp
// During a cutscene or transition
manager.SetTelemetryProvider(new NullTelemetry());  // disables telemetry temporarily
// Later
manager.SetTelemetryProvider(liveTelemetry);        // re-enable live data
```

Any call to `SetTelemetryProvider()` overrides the inspector field until the next scene load or reinitialization.

***

### Summary

| Goal                               | Recommended Provider                                     |
| ---------------------------------- | -------------------------------------------------------- |
| Quick iteration in editor          | **BasicSpecialsTelemetry** sample                        |
| Connect to real data (asset-based) | Subclass **SpecialsTelemetryProvider**                   |
| Integrate live runtime data        | Implement **ISpecialsTelemetry** and inject at runtime   |
| Switch dynamically                 | Use `SetTelemetryProvider()` between different providers |

> **Tip:**\
> For most projects, start with a ScriptableObject subclass for clarity,\
> then move to a runtime provider once your gameplay systems are stable.

***

**In short:**\
Custom telemetry gives your **Special Encounter Manager** true awareness of your game’s pacing - so your boss waves, ambushes, or rare encounters appear exactly when the tension and player condition are right.
