# SpawnOnBake (Sample Script)

## Spawn On Bake (Sample)

**Namespace**: `MegaCrush.NavmeshBaker.Sample`

## Purpose

Safely spawn characters or AI agents after the first successful runtime bake, avoiding errors like:

> *“Failed to create agent because there is no valid NavMesh.”*

***

## How it works

* Subscribes to `BakerEvents.OnBakeCompleted`.
* On each completed bake:
  * Chooses a spawn position (from **Spawn Point** or the GameObject this script is attached to).
  * Calls `NavMesh.SamplePosition()` to snap to a valid NavMesh point.
  * Instantiates the prefab.
* If **Only Once** is enabled, ignores subsequent bakes.

***

## Inspector

* **Prefab (GameObject)**\
  The object to spawn (e.g., enemy, NPC, player). If it’s an AI, it should include a `NavMeshAgent`.
* **Spawn Point (Transform, optional)**\
  If set, the prefab spawns here; otherwise it spawns at this component’s transform.
* **Only Once (bool)**\
  If enabled, spawns on the first completed bake only.
* **Sample Max Distance (float)**\
  Radius around the desired position to search for a valid NavMesh point.
* **Area Mask (int)**\
  NavMesh area mask for sampling (default: `NavMesh.AllAreas`).

***

## Example usage

1. Ensure your scene has a **BakerCoordinator** with a **NavMeshBakeProfile** and **Center Target**.
2. Add one or more **DynamicNavMeshSurface** components for the regions you want baked.
3. Create an empty GameObject and add **SpawnOnBake**.
4. Assign a **Prefab** (e.g., an enemy with `NavMeshAgent`).
5. Optionally assign a **Spawn Point**.
6. Press Play — once the first bake finishes, the prefab spawns on valid NavMesh.

***

## Why it’s useful

* Guarantees AI never spawns off-navmesh.
* Robust for procedural or streaming worlds where navmesh is generated at runtime.
* Demonstrates listening to `BakerEvents.OnBakeCompleted` to gate gameplay logic.

***

## Script

```csharp
using MegaCrush.RuntimeNavmeshBaker;
using UnityEngine;
using UnityEngine.AI;

namespace MegaCrush.NavmeshBaker.Sample
{
    /// <summary>
    /// Spawns a prefab after the first completed runtime bake.
    /// Listens to BakerEvents instead of directly binding to the service.
    /// </summary>
    public sealed class SpawnOnBake : MonoBehaviour
    {
        [Header("Prefab to Spawn")]
        [SerializeField] private GameObject prefab;

        [Header("Spawn Settings")]
        [SerializeField] private Transform spawnPoint;
        [SerializeField] private bool onlyOnce = true;

        [Header("NavMesh Sampling")]
        [SerializeField, Min(0f)] private float sampleMaxDistance = 5f;
        [SerializeField] private int areaMask = NavMesh.AllAreas;

        private bool _hasSpawned;

        private void OnEnable()
        {
            BakerEvents.OnBakeCompleted += HandleBakeCompleted;
        }

        private void OnDisable()
        {
            BakerEvents.OnBakeCompleted -= HandleBakeCompleted;
        }

        private void HandleBakeCompleted(DynamicNavMeshSurface surface, Bounds region, float durationSeconds)
        {
            if (!prefab) return;
            if (onlyOnce && _hasSpawned) return;

            Vector3 desired = spawnPoint ? spawnPoint.position : transform.position;

            if (NavMesh.SamplePosition(desired, out NavMeshHit hit, sampleMaxDistance, areaMask))
            {
                Instantiate(prefab, hit.position, Quaternion.identity);
                _hasSpawned = true;
#if UNITY_EDITOR
                Debug.Log($"[SpawnOnBake] Spawned '{prefab.name}' at {hit.position} (region {region.center}±{region.extents})");
#endif
            }
            else
            {
#if UNITY_EDITOR
                Debug.LogWarning($"[SpawnOnBake] No valid NavMesh within {sampleMaxDistance}m of {desired}. " +
                                 "Increase Sample Max Distance or adjust Spawn Point.");
#endif
            }
        }
    }
}
```
