logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    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.

    Inheritance
    object
    WaveCreator
    Inherited Members
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    object.MemberwiseClone()
    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

    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: created assets/folders are deleted (with Serenity.Global.Infrastructure.Editor.Validation.References.SerenitySafeDeleteScope suppressed — the Wave Set holds live, not-yet-saved references to the wave configs this same call may have just created, which would otherwise trip SerenitySafeDeleteAssetProcessor's referencer scan and silently abort the delete), their Addressables entries removed, and any already-existing asset that was being edited has its pre-call field values restored.

    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
    In this article
    © 2026 Serenity. All Rights Reserved