logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Class SettingsAssetAuthoring

    Shared, engine-side (non-IMGUI) plumbing every single-settings-asset creation wizard needs: resolving the project-wide settings asset the way the runtime picks it (explicit path, the project's own copy over a shipped one, an ambiguity between two project copies, 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.

    Inheritance
    object
    SettingsAssetAuthoring
    Inherited Members
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    object.MemberwiseClone()
    Namespace: Serenity.StructuredPersistence.Infrastructure.Editor.Authoring
    Assembly: Serenity.UnityStructuredPersistence.Infrastructure.Editor.dll
    Syntax
    public static class SettingsAssetAuthoring

    Methods

    EnsureProjectFolderExists(string, ICollection<string>)

    Creates every missing segment of folderPath under the project's Assets folder, appending each newly created folder to createdPaths (shallowest first) so a caller's rollback can delete them in reverse order: assets first (appended last), then folders deepest-to-shallowest. A folder Unity's cache already reports as valid is left untouched. createdPaths takes any ICollection<T> — including Serenity.Global.Infrastructure.Editor.SerenityAssetCreationTransaction.FolderTracking — not just a concrete List<T>.

    Declaration
    public static void EnsureProjectFolderExists(string folderPath, ICollection<string> createdPaths)
    Parameters
    Type Name Description
    string folderPath
    ICollection<string> createdPaths

    IsWellFormedAssetsPath(string)

    Path-shape validation for a folder that will hold generated assets. A folder that does not exist yet is considered valid — EnsureProjectFolderExists(string, ICollection<string>) creates it during creation — this only rejects paths outside the project's Assets folder, or with empty/invalid segments.

    Declaration
    public static bool IsWellFormedAssetsPath(string path)
    Parameters
    Type Name Description
    string path
    Returns
    Type Description
    bool

    RequireProperty(SerializedObject, string)

    UnityEditor.SerializedObject.FindProperty(System.String) returns null — not an exception — for a field name that does not exist, so an unguarded chain like serializedObject.FindProperty("x").intValue = ... turns a renamed [SerializeField] into a NullReferenceException with no indication of which property or asset was involved. This resolves the property or throws a precise, self-diagnosing error instead.

    Declaration
    public static SerializedProperty RequireProperty(SerializedObject serializedObject, string propertyName)
    Parameters
    Type Name Description
    SerializedObject serializedObject
    string propertyName
    Returns
    Type Description
    SerializedProperty

    ResolveSettingsContext(string, string, string)

    Lists every asset of type settingsTypeName by its simple type name, for a caller whose assembly cannot reference the concrete settings type. Unlike ResolveSettingsContext<TSettings>(string, string) this applies no ownership rule: an explicit explicitSettingsAssetPath wins outright; otherwise a search — the whole project, or just searchRootFolder when given — returns the lone match, no match, or flags every path found when more than one exists, shipped copies included, because its callers read the whole candidate set themselves (a collection system's members, the adopted twin beside a shipped default). A caller resolving a singleton wants ResolveSingletonSettingsContext(string, string, string) instead. The resolved asset is loaded via UnityEditor.AssetDatabase.LoadMainAssetAtPath(System.String) since the concrete type is not known here.

    Declaration
    public static SettingsAssetAuthoring.SettingsResolution ResolveSettingsContext(string settingsTypeName, string explicitSettingsAssetPath, string searchRootFolder = null)
    Parameters
    Type Name Description
    string settingsTypeName
    string explicitSettingsAssetPath
    string searchRootFolder
    Returns
    Type Description
    SettingsResolution

    ResolveSettingsContext<TSettings>(string, string)

    Resolves the one project-wide TSettings asset a wizard edits — the same asset the runtime boots on. An explicit explicitSettingsAssetPath wins outright (a test seam and an already-known-asset fast path). Otherwise a search — the whole project, or just searchRootFolder when given — applies the boot-time ownership rule (Serenity.Global.Infrastructure.Editor.SerenitySingletonSettingsAudit.ResolveSelection(System.Collections.Generic.IReadOnlyList{System.String}), the editor mirror of UnitySingletonSettingsLoader): the project's own copy beats a shipped one, so after adoption the adopted copy resolves and the shipped original is not a candidate at all; with no project copy the shipped copy the runtime falls back to resolves; and two or more project copies are the one real ambiguity, reported as every project copy's path — never a shipped one, which is not the author's to delete or merge.

    Declaration
    public static SettingsAssetAuthoring.SettingsResolution<TSettings> ResolveSettingsContext<TSettings>(string explicitSettingsAssetPath, string searchRootFolder = null) where TSettings : Object
    Parameters
    Type Name Description
    string explicitSettingsAssetPath
    string searchRootFolder

    Test seam: narrows the scan to this single Assets-rooted folder instead of the whole project, so a test creating its own TSettings fixtures under a temp folder does not collide with a package-shipped singleton elsewhere in the project. Null (the default) scans the whole project, matching every caller before this parameter existed.

    Returns
    Type Description
    SettingsResolution<TSettings>
    Type Parameters
    Name Description
    TSettings

    ResolveSingletonSettingsContext(string, string, string)

    The non-generic form of ResolveSettingsContext<TSettings>(string, string), for a caller that only knows the settings type by its simple name: the one project-wide singleton asset, by the same boot-time ownership rule — the project's own copy beats a shipped one, with no project copy the shipped copy the runtime falls back to resolves, and only two or more project copies are reported as an ambiguity. The generic overload delegates here, so the two cannot drift apart.

    Declaration
    public static SettingsAssetAuthoring.SettingsResolution ResolveSingletonSettingsContext(string settingsTypeName, string explicitSettingsAssetPath, string searchRootFolder = null)
    Parameters
    Type Name Description
    string settingsTypeName
    string explicitSettingsAssetPath
    string searchRootFolder
    Returns
    Type Description
    SettingsResolution

    ValidateResolution<TSettings>(SettingsResolution<TSettings>, string, SerenityCreationValidationResult)

    The validation pass every by-type settings wizard runs over its own ResolveSettingsContext<TSettings>(string, string) outcome: an ambiguity between the project's own copies is warned about in SettingsAssetAmbiguityNotice's words and nothing else is checked, an already-resolved asset needs no target at all, and only a run that will genuinely create a new asset has its outputFolder shape validated.

    The ambiguity finding is a WARNING, not an error: the wizard's own target gate is what blocks the run until the author picks one of the copies. Both sentences name the asset by Serenity.Global.Infrastructure.Editor.SerenitySingletonSettingsCatalog.AuthorFacingNameOf(System.Type), so the folder rejection and the ambiguity never call the same asset two different things.

    Declaration
    public static void ValidateResolution<TSettings>(SettingsAssetAuthoring.SettingsResolution<TSettings> resolution, string outputFolder, SerenityCreationValidationResult result) where TSettings : Object
    Parameters
    Type Name Description
    SettingsResolution<TSettings> resolution

    The outcome of this wizard's own ResolveSettingsContext<TSettings>(string, string) call.

    string outputFolder

    The folder a new asset would be created in, checked only when the run will actually create one.

    SerenityCreationValidationResult result

    The findings collector this pass reports into.

    Type Parameters
    Name Description
    TSettings

    VerifyAssetWasWrittenToDisk(string)

    UnityEditor.AssetDatabase.CreateAsset(UnityEngine.Object,System.String) logs a native engine error rather than throwing when its destination folder is valid in Unity's cache but has actually been removed from disk. This turns that silent failure into a genuine, catchable exception so a caller's rollback triggers deterministically instead of reporting success over a half-written project.

    Declaration
    public static void VerifyAssetWasWrittenToDisk(string assetPath)
    Parameters
    Type Name Description
    string assetPath
    In this article
    © 2026 Serenity. All Rights Reserved