Class WaveCreator
Generates (or updates) a Wave aggregate asset chain for one stage: an ordered list of
UnityWaveConfigSO assets under <StageFolderPath>/Waves/ and one
UnityWaveSetSO directly under StageFolderPath referencing them, in the exact order
they were authored. Mirrors Serenity.InputGateway.Installation.Editor.Builder.PlayerInputCreator's
multi-asset shape (bottom-up resolve-or-create, then the referencing asset, full rollback on any failure) —
wave configs are the "leaves", the wave set is the "root" that references them, exactly like Device
Filter/Join Gate feeding Routing.
Folder convention, verified against StageSpawnPointProvider, not assumed. The
provider does not require a literal Stages path segment anywhere — it only requires the stage
prefab to sit directly in StageFolderPath and wave assets to sit in
StageFolderPath/Waves/. This engine enforces exactly that (and nothing about the folder's name),
matching what FindStagePrefab(string) and
ScanStagePrefab(string) actually scan — the …/Stages/<Name>/
naming in the cookbooks is a human convention on top of this, not a code requirement.
Spawn-point resolution intentionally bypasses StageSpawnPointProvider's cache —
FindStagePrefab(string)/ScanStagePrefab(string)
are called directly (the same raw scan the cached GetSpawnPointIds wraps) so validation is always
fresh, never stale from a scene/prefab edit the cache has not yet observed via
EditorApplication.projectChanged.
Known, deliberately unfixed semantic gap — ToConfig(). Verified by
reading the source: ToConfig() returns WaveConfig(waveIndex, spawnEntries.Count) — the
domain's TotalActors is the NUMBER OF ENTRIES, not the sum of each entry's Count. A wave
with one entry authored with count = 5 reports TotalActors == 1 at runtime (and
WaveState will consider the wave cleared after a single RecordActorRemoved(), even though
5 actors were actually spawned). This engine does not change that runtime behavior — the fix is out of
scope for this change — but never reports a per-run actor total that relies on it: Preview(Input)
exposes both EntryCount (what ToConfig() will actually use) and
ActorSum (the sum of every entry's authored Count — what a designer
most likely means by "how many actors does this wave spawn") side by side, so the gap is visible at
authoring time instead of silently surprising someone reading a HUD later.
Wiring correction versus Assets/Serenity/Scripts/Unity/Stage/README.md. That README
documents a StageRoot.WaveSet field ("Wave data sourced from StageRoot.WaveSet, fed to wave
service"). Reading the actual StageRoot (Unity/Stage/Infrastructure/Authoring/StageRoot.cs)
on this branch shows no such field — it exposes only stageId. The README is stale. The real
wiring (confirmed in Stage.md §10 step 4 and Wave.md §6) happens exclusively at the
composition root, which must call UnityWaveService.ConfigureFromWaveSet(waveSetSO) and
SetSpawnPointResolver(stageService.SpawnPointResolver) explicitly. Create(Input)'s result
always carries a warning to this effect — creating these assets never wires anything by itself.
A wizard window collecting input and rendering results ships in a separate change; every asset mutation lives here.
Inherited Members
Namespace: Serenity.Wave.Editor.Builder
Assembly: Serenity.UnityWave.Editor.dll
Syntax
public static class WaveCreator
Fields
CompositionRootWiringWarningMessage
The exact prose Create(Input) always adds to Result.Warnings alongside
setting NeedsCompositionRootWiring — a single shared literal so a caller matching
on the message (e.g. to avoid rendering it twice) compares against this constant instead of sniffing a
substring. Public: read by CreateWaveWindow (same assembly) and asserted on directly by
WaveCreatorTests (a separate test assembly).
Declaration
public const string CompositionRootWiringWarningMessage = "These assets do nothing by themselves — the composition root must call UnityWaveService.ConfigureFromWaveSet(waveSet) and SetSpawnPointResolver(stageService.SpawnPointResolver) explicitly (see Stage.md §10 and Wave.md §6)."
Field Value
| Type | Description |
|---|---|
| string |
DefaultStageFolder
Folder a brand-new Wave Set asset is created under when the caller names none.
Declaration
public const string DefaultStageFolder = "Assets/Game/Media/Stages"
Field Value
| Type | Description |
|---|---|
| string |
Methods
Create(Input)
Validates the request, then resolves-or-creates every wave config bottom-up (in Waves order) and finally the Wave Set referencing them in that same order. On any failure every mutation across every touched asset is rolled back: any already-existing asset that was being edited has its pre-call field values restored first — undoing any reference it may hold to an asset this same call just created — and only then are created assets/folders deleted and their Addressables entries removed.
Declaration
public static WaveCreator.Result Create(WaveCreator.Input input)
Parameters
| Type | Name | Description |
|---|---|---|
| WaveCreator.Input | input |
Returns
| Type | Description |
|---|---|
| WaveCreator.Result |
Preview(Input)
Computes what Create(Input) would do without mutating the project.
Declaration
public static WaveCreator.PreviewResult Preview(WaveCreator.Input input)
Parameters
| Type | Name | Description |
|---|---|---|
| WaveCreator.Input | input |
Returns
| Type | Description |
|---|---|
| WaveCreator.PreviewResult |
Validate(Input)
Declaration
public static SerenityCreationValidationResult Validate(WaveCreator.Input input)
Parameters
| Type | Name | Description |
|---|---|---|
| WaveCreator.Input | input |
Returns
| Type | Description |
|---|---|
| SerenityCreationValidationResult |