What’s new? (Upgrade Guide)

What's new, what's changed

Upgrading from 1.3.x → 1.4.0

Version 1.4.0 adds designer-friendly macro control for local (“tile”) spawns, deterministic global seeding, and editor polish. It’s backward compatible - if you don’t opt in, your 1.3 setups keep working.


What changed

🗺️ Region-scale population control (new)

  • RegionPopulationController (scene component) scales each active LocalAreaSpawner via a step-driven density curve, can enable/disable sparse regions, resolves each region’s spawn list from a global RegionSpawnLibrary, and pre-warms pools.

  • RegionSpawnLibrary (ScriptableObject) defines rule-based SpawnEntry mixes per region using tags, director step ranges, and optional weights. Rules can append or replace a region’s authored list; a fallback list covers “no match” cases.

  • SpawnDirector integration so region density & mixes track your intensity steps automatically.

🎲 Deterministic global seeding (new)

  • RuntimeSpawner now supports a Global Seed with a Use Deterministic Seed toggle.

  • Spawns use a reproducible PCG32 stream derived by a seed router from:

    • Global Seed

    • The SpawnEntry’s stable identity

    • Context hints (e.g., SourceName such as wave/table name, region name)

  • Works across Global, Region, and Wave flows; group sizes/order are stable per seed.

  • API: SetGlobalSeed(int seed) and event RuntimeSpawner.onSeedChanged. (Call before any spawns to lock a run.)

🧩 LocalAreaSpawner runtime knobs (non-destructive)

  • DesiredRangeOverride (min,max) + DensityMult are runtime-only. Region loop honors the override; authored Min/Max remain your baseline.

🔄 Region loop awareness

  • RegionSpawnLoop now respects DesiredRangeOverride if set, else uses the authored Min/Max.

🧰 Editor/Inspector updates

  • New inspectors for RegionPopulationController and RegionSpawnLibrary.

  • LocalAreaSpawner inspector shows runtime overrides/readouts for debugging.

  • Unified package header (Docs / API / Support) in inspectors.


Migration steps

  1. Update to 1.4.0. No breaking changes; existing scenes behave like 1.3 unless you opt in to new features.

  2. (Optional) Enable deterministic runs

    • In RuntimeSpawner, enable Use Deterministic Seed and set Global Seed (Inspector), or

    • Call SetGlobalSeed(yourSeed) from your game’s RNG/bootstrap before StartSpawners(). Tip: listen to RuntimeSpawner.onSeedChanged if you mirror the seed elsewhere.

  3. (Optional) Adopt region-scale control

    • Add RegionPopulationController to your scene and assign RuntimeSpawner.

    • (Optional) Assign SpawnDirector so step changes drive density/mixes automatically.

    • Create a RegionSpawnLibrary (Create → Runtime Spawner → Region Spawn Library) and assign it.

  4. Tag your regions

    • Basic: set a Unity Tag on each LocalAreaSpawner GameObject.

    • Multi-tag tiles: implement RegionPopulationController.IRegionTagProvider on a component to return string[].

  5. Author rules in the RegionSpawnLibrary

    • Use Required (ALL) and Any tag filters, Min/Max Step, and optional Weight by Step.

    • Check Replace Instead of Append for rules that should override a tile’s authored list.

    • Add Fallback Entries to avoid empty tiles when nothing matches.

  6. Tune density

    • In RegionPopulationController, adjust the density curve (x=step 0..1 → multiplier) and the Enable Threshold (regions below this are temporarily unregistered).

  7. Playtest

    • Use the LocalAreaSpawner inspector’s runtime panel to confirm DesiredRangeOverride, Density, and resolved entries.

    • Validate global/region caps and each SpawnEntry.maxPopulation.


Notes

  • Back-compat: Without RegionPopulationController, 1.4 behaves like 1.3 (authored Min/Max & lists).

  • Determinism scope: With the same Global Seed, scene content, and timing, spawn choice/order/grouping are reproducible. External nondeterminism (e.g., physics side-effects, asynchronous NavMesh baking, time-based triggers) can still change outcomes.

  • Procedural tiles: Controller auto-tracks regions as they register/unregister via RuntimeSpawner.


Troubleshooting

  • Tile is silent: Density fell below Enable Threshold → controller unregistered that region. Raise threshold or increase curve at that step.

  • New enemy didn’t appear where expected: Check region tags, rule step ranges/weights, and that caps (SpawnEntry.maxPopulation, region/global caps) allow it.

  • Run isn’t deterministic: Ensure Use Deterministic Seed is ON and SetGlobalSeed(...) is called before any spawns; avoid frame-time dependent randomness in your own scripts.


FAQ

Do I have to use the new controller/library? No - opt-in. Existing region setups continue to work.

Will the controller overwrite my authored Min/Max? No. It writes a runtime override; authored values remain your baseline.

What drives “step”? Typically SpawnDirector (intensity profile). If you have your own system, call ApplyStepFromDirector(step, stepsCount) on the controller.

How do I seed the run for reproducible testing? Set Use Deterministic Seed and either set the Global Seed in the inspector or call SetGlobalSeed(seed) during bootstrap (before StartSpawners()).

Can I give a tile multiple semantic tags? Yes - implement IRegionTagProvider on a component and return a string[].

Upgrading from 1.2.x → 1.3.0

Version 1.3.0 introduces two big features and a few quality-of-life updates:

  • NavMesh Placement Policy per Spawn Entry (Require / Prefer / Ignore)

  • Spawn Hints workflow (scene anchors + a settings asset)

  • Inspector polish, new editor menu actions, and clearer debug/warnings

  • Internal: deferred placement queue for “Require” policy, tag-aware wave spawning


What changed

🚦 NavMesh Placement Policy (per Spawn Entry)

  • Require – Only spawn if the position can be projected to the NavMesh now. If not, the request is deferred and retried until success or a retry cap.

  • Prefer (default) – Spawn immediately; if there’s no NavMesh yet, a helper will enable the NavMeshAgent when the mesh appears.

  • Ignore – Skip NavMesh projection entirely (useful for non-NavMesh actors, flying units, FX).

Spawn Hints system

  • EnemySpawnHintPoint (component): place these in the scene to steer where units appear.

    • Per-hint rules: minPlayerDist, maxPlayerDist, denyLineOfSight, requireNavMesh, optional overrideAreaMask, tags.

  • SpawnHintSettings (ScriptableObject): global knobs for search radius, LOS mask, reservation cooldown, etc.

    • Includes Hint-Only mode (skip fallback sampling when no hint qualifies).

    • Includes Ignore Global Min Distance (let close-range hints be used even if spawner’s global min is large).

  • Integrated across Global, Region, and Wave flows.

  • WaveSpawnPoint → Anchor Tags: tags can bias hints (e.g., “Flank”, “Ambush”) during waves.

Editor/Inspector improvements

  • Runtime Spawner inspector: Spawn Hints section with Create & auto-assign settings.

  • SpawnHintSettings inspector: presets, utilities, and warnings.

  • WaveSpawnPoint inspector: simple range + anchor tags UI.

  • Menu:

    • GameObject/Runtime Spawner/Create Wave Spawn Point

    • GameObject/Runtime Spawner/Add Spawn Hint (drops a hint under current selection).


Migration steps

  1. Update the package to 1.3.0.

  2. Update the Runtime Spawner Samples (from Package Manager)

  3. Review your Spawn Entries

    • Open each SpawnEntry and set Placement Policy:

      • Most existing setups should use Prefer (matches prior behavior).

      • If you need deterministic “only on NavMesh” placement at time of spawn, choose Require.

      • If the prefab doesn’t use a NavMeshAgent, choose Ignore.

    • If using Require, optionally set Max Deferred Retries.

  4. (Optional) Adopt Spawn Hints

    • In Runtime Spawner: enable Use Spawn Hints and assign a SpawnHintSettings asset (create from the button if needed).

    • Place a few EnemySpawnHintPoint per tile / encounter space (menu: Add Spawn Hint).

    • For waves, add WaveSpawnPoint children under your WaveTrigger and fill Anchor Tags to bias hint selection.

  5. Check distances

    • Make sure spawner Min Spawn Range doesn’t conflict with your hint distances.

    • If you want very close hints, enable Ignore Global Min Range in SpawnHintSettings.

  6. Test

    • Enable Debug Logs (settings) while tuning.

    • Watch for messages like:

      • “HintOnly: no hint → refusing … spawn.”

      • “No suitable hint found; falling back to sampler.” (off in Hint-Only)

      • Min/max distance conflict warnings.


Notes

  • Performance: Spawn hints use a spatial registry (cell size in settings). Smaller cells = tighter queries but more buckets.

  • Reservation: After a hint is used, it’s soft-reserved for a short cooldown to avoid dog-piling.

  • Deferred queue: With Require, spawns that can’t yet snap to the NavMesh are retried with backoff (configurable retry cap).

  • Waves + Tags: If a WaveSpawnPoint provides tags, matching hints are preferred first.


Before & After

Before (≤1.2.x)

  • All spawns tried to land on the NavMesh; timing quirks sometimes left agents disabled/inactive until mesh appeared.

  • No concept of authored “good spots” - global/region sampling only.

Now (1.3.0+)

  • Clear Require / Prefer / Ignore placement contracts per entry.

  • Author intent with Spawn Hints; optionally Hint-Only to prevent uncontrolled spawns.

  • Wave flows can target hint tags via WaveSpawnPoint anchor tags.


Troubleshooting

  • Nothing spawns with Hint-Only Likely no hint qualifies. Check:

    • Player distance vs. minPlayerDist / maxPlayerDist

    • denyLineOfSight vs. your LOS Block Mask

    • requireNavMesh + NavMesh Sample Max Dist too small

    • Global Min Spawn Range > your hint distances (enable Ignore Global Min Range if needed)

  • Agents never enable with Require Ensure your NavMesh is present/updated at runtime, increase Max Deferred Retries, and verify Area Mask (hint or spawner) includes baked areas.

  • Hints are used too often in one spot Increase Reservation Seconds in SpawnHintSettings.


FAQ

Q: Do I need Spawn Hints? No. They’re optional. Use them where placement really matters (flanks, ambushes), keep sampler fallback for the rest - or enable Hint-Only for fully curated placement.

Q: What does “Prefer scoped first” mean? Hints inside the immediate scope (e.g., wave range or region bounds) are preferred before searching the broader/global radius.

Last updated