> 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/telemetry-providers-samples-and-patterns.md).

# Telemetry Providers - Samples & Patterns

## Telemetry Provider (Optional)

**Why it matters**\
Rules can require *Pressure* or *Average Player HP* values. These are **game-specific** and cannot be hardcoded.\
The manager queries a **Telemetry Provider** at runtime:

* If available → values are compared against rule thresholds.
* If missing → the condition automatically fails (safe default, no spawn).

**Supplying Telemetry**

1. **ScriptableObject Provider (Inspector)**
   * Base: `SpecialsTelemetryProvider` (abstract).
   * Sample: `BasicSpecialsTelemetry` (in `Samples~`) – lets you enter static test values.
   * Workflow:
     * Create via *Assets → Create → MegaCrush → Spawner → Specials Telemetry*.
     * Assign to **Telemetry Provider** field.
2. **Code Provider (ISpecialsTelemetry)**
   * Implement the `ISpecialsTelemetry` interface in your game system (e.g. GameState, DifficultyManager).
   * Inject at runtime:

     ```csharp
     encounterManager.SetTelemetryProvider(myCustomProvider);
     ```

**Telemetry Hooks**

* **Pressure** (float, any scale: 0–1 recommended).
  * e.g. `currentEnemies / maxEnemies`
  * e.g. director intensity level
* **Average Player HP** (float 0–1).
  * e.g. sum of all players’ health% / player count

***

#### System Flow (Telemetry Evaluation)

```
 ┌───────────────────────────────┐
 │   SpecialEncounterManager     │
 │   (runs each eval interval)   │
 └───────────────┬───────────────┘
                 │
                 ▼
     ┌─────────────────────┐
     │   Special Rule(s)   │
     │ - Step Range        │
     │ - Alive Cap         │
     │ - Cooldowns         │
     │ - Telemetry Gates?  │
     └─────────┬───────────┘
               │
   Needs Pressure / Avg HP?
               │
        ┌──────┴────────┐
        ▼               ▼
┌────────────────┐  ┌─────────────────┐
│ Telemetry      │  │ No Provider Set │
│ Provider       │  │ (rule fails     │
│ (SO or code)   │  │ quietly, no     │
│                │  │ spawn occurs)   │
└───────┬────────┘  └─────────────────┘
        │
        ▼
┌──────────────────────────────┐
│ Values returned (Pressure,   │
│ Avg Player HP, etc)          │
└───────────┬──────────────────┘
            │
   Compare vs thresholds
            │
            ▼
 ┌─────────────────────────────┐
 │  Rule passes → spawn agent  │
 │  Rule fails  → no spawn     │
 └─────────────────────────────┘
```

### BasicSpecialsTelemetry (included in Samples)

**Purpose**\
`BasicSpecialsTelemetry` is a minimal **ScriptableObject** provider you can use to test Special Encounter rules without wiring any real game systems. It exposes two sliders-**Pressure** and **Average Player HP-**&#x74;hat the `SpecialEncounterManager` will read during rule evaluation.

```csharp
// Samples~/.../BasicSpecialsTelemetry.cs
using UnityEngine;

namespace MegaCrush.Spawner.Samples
{
    [CreateAssetMenu(menuName = "Runtime Spawner/Specials Telemetry/Basic Sample")]
    public sealed class BasicSpecialsTelemetry : SpecialsTelemetryProvider
    {
        [Range(0f, 1f)] public float pressure = 0f;
        [Range(0f, 1f)] public float averagePlayerHP = 1f;

        public override bool TryGetPressure(out float value) { value = pressure; return true; }
        public override bool TryGetAveragePlayerHP(out float value) { value = averagePlayerHP; return true; }
    }
}
```

#### When to use it

* You’re validating **Special Rules** (thresholds, cooldowns, step ranges) before your gameplay systems are ready.
* You want to see how changing **Pressure** or **Avg HP** impacts encounter timing in real time.
* You’re building automated tests around rules that need deterministic values.

#### Create & Assign (Quickstart)

1. **Create the asset**\
   `Assets → Create → Runtime Spawner → Specials Telemetry → Basic Sample`
2. **Assign it on the Manager**\
   In the **Special Encounter Manager** inspector, set **Telemetry Provider** to your new `BasicSpecialsTelemetry` asset.
3. **Play Mode**\
   Tweak the **Pressure** and **Average Player HP** sliders on the asset while the game runs and observe:
   * Rule pass/fail based on thresholds
   * Spawn frequency and tags
   * “Runtime Status” in the Manager inspector (Next/Last spawn times)

#### What the sliders mean

* **Pressure**: Any scalar you choose (commonly 0–1). Higher = more stress/intensity.
* **Average Player HP**: Mean health across players (0–1). Lower = team is hurt.

> Note: Rule checks read these values via the provider on each evaluation. If a rule requires telemetry and **no provider** is assigned, that condition **fails safely** (no spawn).

***

### Extending Beyond the Sample

#### Base Class: `SpecialsTelemetryProvider`

Use this when you want an **inspector-driven** provider (SO asset) that pulls values from your game.

```csharp
public abstract class SpecialsTelemetryProvider : ScriptableObject, ISpecialsTelemetry
{
    public abstract bool TryGetPressure(out float value);
    public abstract bool TryGetAveragePlayerHP(out float value);
}
```

**Pattern: SO provider that reads from your systems**

```csharp
using UnityEngine;

public sealed class GameLinkedTelemetry : SpecialsTelemetryProvider
{
    public override bool TryGetPressure(out float value)
    {
        // Example: read from a singleton/service
        value = MyGame.Difficulty.CurrentPressure01;
        return true;
    }

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

Pros

* Easy to **swap** per scene/profile.
* Editable references in the inspector.
* Works with addressables/asset workflows.

Cons

* Slightly more setup than a pure code approach.

#### Interface: `ISpecialsTelemetry`

Use this when you want to inject a **pure code** provider at runtime.

```csharp
public interface ISpecialsTelemetry
{
    bool TryGetPressure(out float value);
    bool TryGetAveragePlayerHP(out float value);
}
```

**Pattern: Code provider injected at runtime**

```csharp
public sealed class RuntimeTelemetry : ISpecialsTelemetry
{
    private readonly DifficultyManager _dm;
    private readonly PlayerService _players;

    public RuntimeTelemetry(DifficultyManager dm, PlayerService players)
    { _dm = dm; _players = players; }

    public bool TryGetPressure(out float value)
    {
        value = _dm.Pressure01;
        return true;
    }

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

// Injection
var mgr = FindObjectOfType<SpecialEncounterManager>();
mgr.SetTelemetryProvider(new RuntimeTelemetry(difficulty, players));
```

Pros

* No assets required.
* Easy to **unit test**.
* Perfect for service/DI architectures.

Cons

* Not directly swappable via inspector.

***

### Choosing a Scale

* **Recommended**: Normalize to **0–1** for both Pressure and Avg HP so thresholds are easy to reason about.
* If you use a different scale, keep it **consistent** across rules and providers.

***

### Common Rule Examples (With Telemetry)

* **Miniboss under pressure**
  * `Min Pressure ≥ 0.75`, `Step Range 3–99`, `Cooldown 180s`
* **Flankers only when team is healthy**
  * `Min Avg HP ≥ 0.6`, `Require No LOS = true`, `Distance 18–32m`
* **Snipers when players are low**
  * Use *reverse* gate by creating two variants:
    * Rule A (sniper): `Min Pressure ≥ 0.5`, `Min Avg HP ≥ 0.3`
    * Baseline population reduces to make room (via director/other rules)

***

### Troubleshooting

* **Nothing spawns despite rules valid**
  * Check **Max Simultaneous Specials** and **Min Gap Seconds** on the Profile.
  * Ensure **alive cap** for the rule isn’t already reached.
  * Verify **Step Range** matches the Director’s current step.
  * Confirm **Telemetry Provider** is assigned (or injected) if the rule uses telemetry.
* **Require No LOS never passes**
  * Set **Occluder Mask** to include geometry layers that should block line‑of‑sight.
  * Verify anchors are placed behind occluders relative to the player.
* **Provider values aren’t changing**
  * If using an SO provider, you can tweak asset fields **at runtime**.
  * If using a code provider, ensure you call `SetTelemetryProvider(...)` **after** your systems are initialized and that your getters return updated values each frame.

***

### Quick Checklist

1. Create a **Special Profile**, add rules with telemetry thresholds.
2. Assign **BasicSpecialsTelemetry** to the Manager to validate behavior.
3. Replace the sample with a **Game‑linked SO provider** or **code provider** implementing `ISpecialsTelemetry`.
4. Use the Manager’s **Runtime Status** and **Force Roll Now** to iterate quickly.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://megacrush.gitbook.io/megacrush-unity-assets/runtime-spawner/runtime-spawner-user-manual/getting-started/specials-telemetry-system/telemetry-providers-samples-and-patterns.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
