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
LocalAreaSpawnervia 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
SpawnEntrymixes 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 identityContext 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 eventRuntimeSpawner.onSeedChanged. (Call before any spawns to lock a run.)
🧩 LocalAreaSpawner runtime knobs (non-destructive)
DesiredRangeOverride (min,max)+DensityMultare runtime-only. Region loop honors the override; authored Min/Max remain your baseline.
🔄 Region loop awareness
RegionSpawnLoopnow respectsDesiredRangeOverrideif 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
Update to 1.4.0. No breaking changes; existing scenes behave like 1.3 unless you opt in to new features.
(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 beforeStartSpawners(). Tip: listen toRuntimeSpawner.onSeedChangedif you mirror the seed elsewhere.
(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.
Tag your regions
Basic: set a Unity Tag on each
LocalAreaSpawnerGameObject.Multi-tag tiles: implement
RegionPopulationController.IRegionTagProvideron a component to return string[].
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.
Tune density
In RegionPopulationController, adjust the density curve (x=step 0..1 → multiplier) and the Enable Threshold (regions below this are temporarily unregistered).
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[].
Last updated