logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Class 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.

    Inheritance
    object
    SettingsAssetResolution
    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 SettingsAssetResolution

    Methods

    DescribeWriteBoundaryCollision<TSettings>(string, string, string)

    Pure query form of ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool)'s own write-boundary check: describes the exact same collision, without throwing — null when nothing collides, INCLUDING the index-lag case where the planned path already holds the exact asset being resolved (same type, same Id ordinally). Lets a preflight validator (see ValidateNoWriteBoundaryCollision<TSettings>(string, string, string, SerenityCreationValidationResult)) surface this refusal to the author as a blocking validation error BEFORE the primary action ever calls ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool), instead of only after a rolled-back transaction. The message text is built in DescribeCollision(string, string) so the thrown and the validated wording never drift apart.

    Declaration
    public static string DescribeWriteBoundaryCollision<TSettings>(string folderPath, string id, string fileNameFallback) where TSettings : ScriptableObject, IFoundationSettings
    Parameters
    Type Name Description
    string folderPath
    string id
    string fileNameFallback
    Returns
    Type Description
    string
    Type Parameters
    Name Description
    TSettings

    PlannedAssetPath(string, string, string)

    The path a by-type resolve-or-create run would write a NEW asset to: explicitAssetPath when given, otherwise fallbackFolderPath/fallbackFileName.asset. Pure — computes the path without resolving, creating, or ensuring anything, so ResolveOrCreateAtPath<TSettings>(SettingsResolution<TSettings>, string, string, string, SerenityAssetCreationTransaction, out bool) and a caller's own read-only Preview both compute the identical path from one place instead of two.

    Declaration
    public static string PlannedAssetPath(string explicitAssetPath, string fallbackFolderPath, string fallbackFileName)
    Parameters
    Type Name Description
    string explicitAssetPath
    string fallbackFolderPath
    string fallbackFileName
    Returns
    Type Description
    string

    PlannedByIdPath(string, string, string)

    The path a by-id resolve-or-create run would write a NEW asset to: folderPath/ {id sanitized, falling back to fileNameFallback}.asset. Pure — computes the path without resolving, creating, or ensuring anything, so ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool) and a caller's own read-only Preview both compute the identical path from one place instead of two.

    Declaration
    public static string PlannedByIdPath(string folderPath, string id, string fileNameFallback)
    Parameters
    Type Name Description
    string folderPath
    string id
    string fileNameFallback
    Returns
    Type Description
    string

    ResolveOrCreateAtPath<TSettings>(SettingsResolution<TSettings>, string, string, string, SerenityAssetCreationTransaction, out bool)

    Returns resolution.Existing untouched when set — no folder is ensured and nothing is written to disk; otherwise creates a new TSettings at explicitAssetPath when given, or at fallbackFolderPath/fallbackFileName.asset otherwise.

    The folder ensured is always the CHOSEN path's own parent folder, not necessarily fallbackFolderPath itself — an explicit path pointing somewhere else is honored as given, exactly like the four private copies it is extracted from. The caller is responsible for sanitizing fallbackFileName (via FileNameSafe(string, string) or equivalent) before calling, since the desired sanitization fallback differs per caller.

    Unlike ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool) this never assumes IFoundationSettings and never assigns an Id or a Guid — the caller seeds both on the returned asset AFTER this call, exactly like the four copies do.

    Declaration
    public static TSettings ResolveOrCreateAtPath<TSettings>(SettingsAssetAuthoring.SettingsResolution<TSettings> resolution, string explicitAssetPath, string fallbackFolderPath, string fallbackFileName, SerenityAssetCreationTransaction transaction, out bool createdNew) where TSettings : ScriptableObject
    Parameters
    Type Name Description
    SettingsResolution<TSettings> resolution
    string explicitAssetPath
    string fallbackFolderPath
    string fallbackFileName
    SerenityAssetCreationTransaction transaction
    bool createdNew
    Returns
    Type Description
    TSettings
    Type Parameters
    Name Description
    TSettings

    ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool)

    Returns the existing TSettings asset in folderPath (and its subfolders) whose Id equals id ordinally, so the caller updates it in place; otherwise creates one named after id — falling back to fileNameFallback when the Id yields no usable file name — assigns it a fresh Guid, and hands the path to transaction, which registers it with Addressables on commit and deletes it on rollback.

    The folder is ensured on the create path even when the caller already ensured it. That is not a redundant write: UnityEditorUtils.ResourceUtils.EnsureFolder returns before touching the AssetDatabase — and before recording anything for rollback — as soon as UnityEditor.AssetDatabase.IsValidFolder(System.String) reports the folder exists. Paying that check unconditionally is what lets one method serve callers that ensure beforehand and callers that do not, instead of two near-identical overloads encoding nothing but the caller's own statement order.

    Declaration
    public static TSettings ResolveOrCreateByIdInFolder<TSettings>(string folderPath, string id, string fileNameFallback, SerenityAssetCreationTransaction transaction, out bool createdNew) where TSettings : ScriptableObject, IFoundationSettings
    Parameters
    Type Name Description
    string folderPath
    string id
    string fileNameFallback
    SerenityAssetCreationTransaction transaction
    bool createdNew
    Returns
    Type Description
    TSettings
    Type Parameters
    Name Description
    TSettings

    ValidateCreateDestinationFolder<TSettings>(string, IEnumerable<string>, string, SerenityCreationValidationResult)

    ValidateCreateDestinationFolder<TSettings>(string, string, string, SerenityCreationValidationResult) for a run that resolves-or-creates SEVERAL assets by Id within one folder: the folder is a destination as soon as one of ids resolves nothing there, and the rejection is stated once.

    Declaration
    public static void ValidateCreateDestinationFolder<TSettings>(string folderPath, IEnumerable<string> ids, string fieldName, SerenityCreationValidationResult result) where TSettings : ScriptableObject, IFoundationSettings
    Parameters
    Type Name Description
    string folderPath
    IEnumerable<string> ids
    string fieldName
    SerenityCreationValidationResult result
    Type Parameters
    Name Description
    TSettings

    ValidateCreateDestinationFolder<TSettings>(string, string, string, SerenityCreationValidationResult)

    Adds Serenity.Global.Infrastructure.Editor.SerenityProjectOutputFolderRules's rejection as a blocking error when this run would CREATE a new TSettings in folderPath and that folder is not one a project may write generated assets into — the destination half of the shipped-content contract, for the creators that resolve-or-create by Id within one folder.

    Deliberately a no-op when the by-Id lookup already resolves an asset there: that folder is then not a destination at all, it is where an asset this run UPDATES happens to live, and whether the update may proceed is Serenity.Global.Infrastructure.Editor.ShippedContentWriteGate's question — ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool) asks it through Serenity.StructuredPersistence.Infrastructure.Editor.Authoring.SettingsAssetResolution.OpenForWriting``1(``0) a moment later. Rejecting the folder here instead would refuse an update the author has confirmed in the tool's own window, which is the one way through that gate deliberately leaves open.

    Declaration
    public static void ValidateCreateDestinationFolder<TSettings>(string folderPath, string id, string fieldName, SerenityCreationValidationResult result) where TSettings : ScriptableObject, IFoundationSettings
    Parameters
    Type Name Description
    string folderPath
    string id
    string fieldName

    The folder picker as the author reads it on the tool's own form.

    SerenityCreationValidationResult result
    Type Parameters
    Name Description
    TSettings

    ValidateNoWriteBoundaryCollision<TSettings>(string, string, string, SerenityCreationValidationResult)

    Adds DescribeWriteBoundaryCollision<TSettings>(string, string, string)'s message as a blocking error on result when the by-Id lookup finds nothing in folderPath AND a different asset (or a different asset TYPE entirely) already occupies the exact file path a create would plan — the same refusal ResolveOrCreateByIdInFolder<TSettings>(string, string, string, SerenityAssetCreationTransaction, out bool) throws on, surfaced to a wizard's own Validate so the author sees it on the Id field before ever pressing the primary button, rather than as a rolled-back transaction's error message afterward. A no-op when id is blank (nothing has been typed yet to collide with) or when the by-Id lookup already resolves an asset to update in place (an update never plans a colliding create path).

    Declaration
    public static void ValidateNoWriteBoundaryCollision<TSettings>(string folderPath, string id, string fileNameFallback, SerenityCreationValidationResult result) where TSettings : ScriptableObject, IFoundationSettings
    Parameters
    Type Name Description
    string folderPath
    string id
    string fileNameFallback
    SerenityCreationValidationResult result
    Type Parameters
    Name Description
    TSettings
    In this article
    © 2026 Serenity. All Rights Reserved