logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Namespace Serenity.StructuredPersistence.Infrastructure.Editor.Authoring

    Classes

    SettingsAssetAuthoring

    Shared, engine-side (non-IMGUI) plumbing every single-settings-asset creation wizard needs: resolving the project-wide settings asset (explicit path, single existing asset, or none), Assets-path shape validation, recursive folder creation with a rollback-friendly created-paths trail, and a hardened asset-write check. Extracted from Serenity.GameProgress.Infrastructure.Editor.Builder.GameProgressCreator and Serenity.GameSave.Infrastructure.Editor.Builder.GameSaveCreator, which were byte-for-byte duplicating this exact logic. Serenity.Leaderboard.Infrastructure.Editor.Builder.LeaderboardCreator exposes ResolveSettingsContext publicly like every other adopter, and resolves-or-creates its settings asset through ResolveOrCreateAtPath<TSettings>(SettingsResolution<TSettings>, string, string, string, SerenityAssetCreationTransaction, out bool); its board-uniqueness and view/menu-option resolution live on top of both and this shared helper knows nothing about them.

    SettingsAssetAuthoring.SettingsResolution

    Non-generic counterpart of SettingsAssetAuthoring.SettingsResolution<TSettings> for a caller that only knows the settings type by its simple name — e.g. an attribute-declared installable system whose assembly cannot reference the concrete settings type (see SerenityInstallableSystemAttribute).

    SettingsAssetAuthoring.SettingsResolution<TSettings>

    Where a settings asset of type TSettings was found, if anywhere.

    SettingsAssetRelocation

    Shared move-out-of-package engine for a by-type settings creator that adopts SerenityWizardTargetAsset.MoveOutOfPackage: validating a requested move as errors a caller can surface before its own Create ever runs (mirroring Serenity.Global.Infrastructure.Editor.SerenityPackageContentRelocator.MoveIntoFolder(System.String,System.String,Serenity.Global.Infrastructure.Editor.SerenityAssetCreationTransaction)'s own guards), and performing the move itself inside the caller's own Serenity.Global.Infrastructure.Editor.SerenityAssetCreationTransaction. MoveIntoPlannedFolder(string, string, SerenityAssetCreationTransaction) asserts the relocated path lands exactly where the caller's planned settings asset path said it would — see Serenity.Global.Infrastructure.Editor.SerenityWizardTargetAsset.PlannedTargetPath(System.String,System.String)'s doc for why the two must always agree BY CONSTRUCTION, not by coincidence.

    A caller's own Create wants MoveIfRequested(string, string, SerenityAssetCreationTransaction), not MoveIntoPlannedFolder(string, string, SerenityAssetCreationTransaction) directly: it folds the "was a move even requested" branch and the SettingsAssetRelocation.PendingMove bookkeeping a caller would otherwise repeat around the move into one call, one held value, and one RecordOnto(SerenityCreationResult) call after commit — GameGraphicsSettingsCreator, LeaderboardCreator and LocalizationSettingsCreator all adopt it identically: one Validate(string, string, SerenityCreationValidationResult) call inside their own Validate, one MoveIfRequested(string, string, SerenityAssetCreationTransaction) call as the first step inside their own Create (before settings-context resolution runs), one RecordOnto(SerenityCreationResult) call right after their transaction commits.

    SettingsAssetResolution

    Resolve-or-create for a settings asset identified BY ID WITHIN A FOLDER — the shape every creator that authors many assets of one type needs, and the counterpart to ResolveSettingsContext<TSettings>(string, string), which answers the opposite question: where is the ONE project-wide settings asset?

    Replaces the byte-identical private helper WaveCreator, SequencePlayerCreator and PlayerInputCreator each declared, plus the concrete twins in InitializationPipelineProfileCreator and LoggingProfileCreator. Those five differed only in whether the fallback file name arrived as a parameter or as a class constant.

    Lives beside SettingsAssetAuthoring rather than beside Serenity.Global.Infrastructure.Editor.SerenityAssetIdLookup because it needs EnsureProjectFolderExists(string, ICollection<string>) and VerifyAssetWasWrittenToDisk(string), and this assembly already depends on the one those two lookups live in — the reverse would be a cycle. Reaching past EnsureProjectFolderExists to the EnsureFolder it wraps would drop its Assets-path-shape guard, which for some callers is the only validation the path gets.

    ResolveOrCreateAtPath<TSettings>(SettingsResolution<TSettings>, string, string, string, SerenityAssetCreationTransaction, out bool) is the by-type twin: resolve-or-create for the ONE project-wide settings asset a wizard resolves via ResolveSettingsContext<TSettings>(string, string), identified by an explicit or fallback path rather than by Id within a folder. It is extracted from the byte-identical private helper GameGraphicsSettingsCreator, LocalizationSettingsCreator, LoggingProfileCreator and GameProgressCreator each declare today; the adopter PRs migrate them to it. Like ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool) it ensures the folder lazily — only on the create path, never when an existing asset is returned — but it constrains only UnityEngine.ScriptableObject, not IFoundationSettings, so it never assigns an Id or a Guid; the caller seeds both on the returned asset afterward, exactly like the four copies do.

    SingletonSettingsCreationEngine<TSettings, TInput, TResult>

    Template-method engine shared by every "create or update the ONE project-wide settings asset of this module" wizard: identity validation, target validation (folder shape and path collision), the transaction-backed creation with rollback, Addressables registration under the module's label, and the in-place update that restores the asset when a step after it fails. A concrete engine supplies only what genuinely differs between modules — its label, its default asset name, how it reads in a message, and which fields the input writes onto the asset.

    Extracted from the ten near-identical *SettingsCreator classes (MenuServiceSettingsCreator and ModalServiceSettingsCreator matched 85-94% line for line; five of the ten declared a byte-identical ResolveNewAssetPath). ModalCreator is deliberately not one of them: it authors many drafts, not one singleton, and belongs to ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool)'s shape instead.

    Adopt it the way BatchSoundEffectImporter adopts BatchAudioAssetImportEngine{TItem,TInput,TResult,TAsset}: keep the module's public static class as the caller-facing surface, hold one private sealed class Engine instance behind it, and forward each public member in one line — the windows and tests that already call the static creator never change.

    The Id and the Guid are the engine's business, not a subclass's: it writes Id on both the create and the update path and seeds a fresh Guid exactly once, on creation. ApplyFields(TInput, TSettings) is therefore only ever handed the module's own fields to write, which is why the same override serves both paths.

    SingletonSettingsInput

    The request shape every project-wide-singleton settings wizard shares: which existing asset to edit (if any), where a brand-new one goes, what it is called, the identifier written onto it, and the Addressables policy. Base for each module's own Input type, which adds only its own fields — the counterpart to SingletonSettingsResult and the input half of SingletonSettingsCreationEngine<TSettings, TInput, TResult>.

    SingletonSettingsResult

    The outcome shape every project-wide-singleton settings wizard shares, on top of what Serenity.Global.Infrastructure.Editor.SerenityCreationResult already carries: where the settings asset ended up, and whether the run edited one that already existed instead of writing a new one. Base for each module's own Result type — the result half of SingletonSettingsCreationEngine<TSettings, TInput, TResult>.

    StructuredBackendAssetInstaller

    Writes one structured backend definition to disk for a creation run: builds the asset, parks whatever already stands at its path when the run is a "Replace Existing Backend", creates the asset, proves it reached disk, and registers it with the run's Serenity.Global.Infrastructure.Editor.SerenityAssetCreationTransaction.

    The one implementation of a pipeline that used to live, byte-identical, in four creators (GameProgressCreator, GameSaveCreator, LeaderboardCreator, LoggingProfileCreator) as a MoveExistingBackendToTempPathIfNeeded / CleanUpMovedBackends / RestoreMovedBackends trio over a private List<(TempPath, OriginalPath)> ledger. That duplication was the highest-blast-radius kind: the ledger holds the user's existing backend asset — the only copy of it, moved rather than copied — so a rollback-ordering fix applied to one copy left the other three still able to lose it. The park half lives here; the unwind half lives on the transaction, as Serenity.Global.Infrastructure.Editor.SerenityAssetCreationTransaction.TrackReplacedAsset(System.String,System.String), because only the transaction knows when the original path is free again.

    Parking rather than deleting is the point of the flow: a same-name replace must not destroy the old backend before the whole run is known to succeed, and UnityEditor.AssetDatabase.MoveAsset(System.String,System.String) relocates it under its own GUID, so an in-memory reference a creator captured for its rollback stays valid.

    StructuredBackendAuthoringFactory

    Engine-side (non-IMGUI) half of the shared backend authoring step: per-kind connection defaults, validation, and shared backend asset construction. Extracted from Serenity.Leaderboard.Infrastructure.Editor.Builder.LeaderboardCreator so the GameSave and GameProgress creation wizards do not each duplicate this logic a second and third time; Leaderboard's own copy is left untouched to avoid touching its already-tested code.

    StructuredBackendAuthoringFields

    Every connection field any StructuredBackendAuthoringKind backend asset can carry. A wizard window holds one of these as a [SerializeField] and hands it to StructuredBackendAuthoringGui/StructuredBackendAuthoringFactory, so the shared backend authoring step (cards, fields, validation, asset construction) is written once instead of duplicated per consumer wizard (GameSave, GameProgress). Table/collection name is deliberately NOT here — it belongs to the consumer's own settings asset, not to the backend.

    StructuredBackendAuthoringGui

    The shared IMGUI half of the backend authoring step: the four backend cards, the kind-specific fields, and the scripting-define/secret-in-plaintext warnings — extracted from CreateLeaderboardWindow's Backend step so the GameSave and GameProgress wizards draw the identical UI without duplicating it. Pure presentation over StructuredBackendAuthoringFields; all validation and asset construction live in StructuredBackendAuthoringFactory.

    Structs

    SettingsAssetRelocation.PendingMove

    A move MoveIfRequested(string, string, SerenityAssetCreationTransaction) already performed, held by the caller across its own try/commit block until RecordOnto(SerenityCreationResult) can run — recording earlier would report a move that a LATER step's failure then rolled back. None is both the "nothing was requested" sentinel and this type's own default value, so a caller that never assigns one still gets a safe no-op from RecordOnto(SerenityCreationResult).

    StructuredBackendAuthoringFactory.KindDefaults

    Per-kind connection defaults offered by a wizard's Backend step, keyed by StructuredBackendAuthoringKind.

    Enums

    StructuredBackendAuthoringKind

    Editor-only authoring choice shared by every structured-store consumer's creation wizard (GameSave, GameProgress): which shared UnityStructuredBackendDefinition subtype the wizard creates and assigns to the consumer's settings asset. Purely a wizard concern — the runtime always dispatches on the backend asset's concrete type, never on this enum. Every kind creates an explicit backend asset, including PlayerPrefs.

    In this article
    © 2026 Serenity. All Rights Reserved