How to: Using Specials Telemetry

Prerequisites

  • Runtime Spawner is in your scene and calls Init(...)Begin() on startup.

  • A SpecialEncounterManager is present and assigned a SpecialProfile with at least one SpecialRule.

  • Your project has TextMeshPro and the Diagnostics HUD in the scene (or you’ve added it).

1) Choose how you’ll provide telemetry

You can feed “Pressure” and “Average Player HP” into specials via either:

  • Option A (Inspector / ScriptableObject): subclass SpecialsTelemetryProvider and assign the asset on the manager.

  • Option B (Code / Interface): implement ISpecialsTelemetry and inject the instance at runtime.

Both options can coexist; if you call SetTelemetryProvider(...) at runtime, that overrides the SO field.


2) Option A — ScriptableObject provider (Inspector setup)

  1. Create a provider asset:

    • Right‑click in Project: Create → MegaCrush → Spawner → Specials Telemetry (use your subclass or the BasicSpecialsTelemetry sample under Samples~ for testing).

  2. Assign it:

    • Select your SpecialEncounterManager in the scene.

    • Drag the provider asset into the Telemetry Provider field.

  3. Hook your real data (recommended):

    • In your subclass of SpecialsTelemetryProvider, implement:

      public override bool TryGetPressure(out float value) { /* set value */ }
      public override bool TryGetAveragePlayerHP(out float value) { /* set value */ }
    • Pull values from your game systems (difficulty/AI director, health system, etc.).

Notes:

  • The sample asset exposes static sliders—useful to prove the pipeline works, then replace with a real subclass.


3) Option B — Code provider (runtime injection)

  1. Implement the interface anywhere in your game:

    using MegaCrush.Spawner;
    
    public sealed class MyTelemetry : ISpecialsTelemetry
    {
        public bool TryGetPressure(out float value)
        {
            // Example: normalized by your max enemy budget
            value = CurrentEnemyCount / (float)MaxEnemyBudget;
            return true;
        }
    
        public bool TryGetAveragePlayerHP(out float value)
        {
            // Example: average over all active players (0..1)
            value = ComputeAveragePlayerHealthNormalized();
            return true;
        }
    }
  2. Inject it before specials begin:

    // wherever you bootstrap spawner systems after SpecialEncounterManager.Init(...)
    var specials = FindAnyObjectByType<SpecialEncounterManager>();
    specials.SetTelemetryProvider(new MyTelemetry());

4) Configure rules that use telemetry

Open your SpecialProfile and for any SpecialRule you want gated:

  • Set minPressure to a threshold (e.g., 0.75).

  • Set minAvgPlayerHP (0..1) if you want to avoid spawning when players are very low.

  • Ensure stepRange, maxAlive, evalEverySeconds, cooldownSeconds, distanceRange, and spawnTag are configured sensibly.

Behavior:

  • If a rule requires telemetry but no provider is available, the rule’s condition fails (special won’t spawn). Everything else continues to work.


If you’ve updated the HUD with the added fields:

  • Assign in the HUD inspector:

    • SpecialsTimerText

    • SpecialsLastSpawnText

    • SpecialsNextTagText

  • In play mode, you’ll see:

    • “Specials: next in Xs (at Y.s)” — the next evaluation ETA.

    • “Last special: Ns ago” — last successful special time.

    • “Next Tag: …” — the planned tag (best effort debug hint).

The Population section’s Total Active shows the live count, and the per‑source breakdown helps confirm sources (Global/Region/Wave/Special).


6) Quick test workflow

  1. Put your player into the scene and ensure RuntimeSpawner knows the PlayerTransform.

  2. Use the sample BasicSpecialsTelemetry asset (Option A) and set:

    • pressure = 0.9

    • averagePlayerHP = 1.0

  3. In your SpecialProfile, set one rule with:

    • minPressure = 0.8

    • minAvgPlayerHP = 0.5

    • Reasonable evalEverySeconds (e.g., 1–3s) and cooldownSeconds (e.g., 10–20s).

  4. Enter Play:

    • Watch the HUD: ETA should count down; last spawn updates when a special appears.

    • If you’re step‑gated, advance your Director step and verify the HUD updates “Intensity Step”.

Tip (Editor only): you can use the context menu Force Specials Roll Now on SpecialEncounterManager to arm all rules immediately. This is wrapped in #if UNITY_EDITOR and excluded from builds.


7) Troubleshooting

  • “Specials: (unscheduled)” Likely all rules are ineligible (step gating, no rules, or evaluation times in the future). Advance the Director step or reduce thresholds.

  • No spawns despite positive thresholds Check:

    • minGapSeconds on the profile (global cooldown).

    • maxAlive for the rule (you may be at cap).

    • Anchor availability: ensure WaveSpawnPoints exist with matching spawnTag, correct distanceRange, and LOS setting (if requireNoLOS, confirm an occluder actually blocks).

    • Telemetry provider returns true and supplies values that meet thresholds.

  • HUD “Total Active” climbs forever Ensure you’re on the updated HUD that uses _pop.Current for the live count.

  • Nothing happens after scene load Confirm your flow calls: RuntimeSpawner.Init(...)SpecialEncounterManager.Init(...) (done by spawner) → RuntimeSpawner.StartSpawners()SpecialEncounterManager.Begin() (called by spawner).

Last updated