Class PrefetchPolicyCreator
Generates (or updates) a PrefetchPolicyRegistry asset and the set of PrefetchPolicyProfile assets it references, from a single description. Mirrors Serenity.GameCamera.Infrastructure.Editor.Builder.GameCameraSettingsCreator: static class, Input/Result DTOs, Validate, Create with created-paths rollback on failure — resolved and folder-provisioned through the shared SettingsAssetAuthoring engine rather than a private copy of its logic. Every validation rule lives in PrefetchPolicyValidator instead — this class keeps only resolution and the actual write path.
Unlike the registry — a single project-wide asset resolved the same way Serenity.GameCamera.Infrastructure.Settings.UnityGameCameraSettings is — the profiles are a set of N assets. A row built from the flat PrefetchPolicyCreator.Input/PrefetchPolicyCreator.ProfileRow shape (the Create(Input) entry point — headless/programmatic callers) resolves to an existing PrefetchPolicyProfile asset with a matching Id already living in ProfilesFolderPath (updated in place) or a brand-new asset created there — an intentional, documented "update by Id" feature. A row CreatePrefetchPolicyWindow itself seeds from an existing profile is different: it stays bound to THAT SAME asset regardless of what its Id field gets retyped to — see CreateFromDrafts(IReadOnlyList<SerenityWizardScratchDraft<PrefetchPolicyProfile>>, string, string, bool, UnboundRowWriteMode)'s own doc for the identity rule and the finding it closes.
CreatePrefetchPolicyWindow only collects input and renders results; every asset mutation lives here.Inherited Members
Namespace: Serenity.AssetPrefetcher.Infrastructure.Editor.Builder
Assembly: Serenity.UnityAssetPrefetcher.Infrastructure.Editor.dll
Syntax
public static class PrefetchPolicyCreator
Fields
DefaultOutputFolder
Folder brand-new profile/registry assets are created under when the caller names none.
Declaration
public const string DefaultOutputFolder = "Assets/Game/Media/AssetPrefetcher"
Field Value
| Type | Description |
|---|---|
| string |
DefaultProfileId
The Id the registry's GetDefault() looks up.
Declaration
public const string DefaultProfileId = "default"
Field Value
| Type | Description |
|---|---|
| string |
ProfileAssetFileNameFallback
Fallback file name for a brand-new profile asset when a Id sanitizes to nothing usable.
Declaration
public const string ProfileAssetFileNameFallback = "PrefetchPolicyProfile"
Field Value
| Type | Description |
|---|---|
| string |
RegistryAssetFileNameFallback
Fallback (and only) file name for a brand-new registry asset — the registry carries no authored "name" field, so this is always the resolved file name when RegistryAssetPath is empty.
Declaration
public const string RegistryAssetFileNameFallback = "PrefetchPolicyRegistry"
Field Value
| Type | Description |
|---|---|
| string |
RuntimeMinimumMaxSizeMB
The runtime service floor-clamps the memory budget to this many megabytes.
Declaration
public const int RuntimeMinimumMaxSizeMB = 16
Field Value
| Type | Description |
|---|---|
| int |
Methods
Create(Input)
Validates the request, then maps every PrefetchPolicyCreator.ProfileRow onto a throwaway scratch draft and
hands the set to CreateFromDrafts(IReadOnlyList<SerenityWizardScratchDraft<PrefetchPolicyProfile>>, string, string, bool, UnboundRowWriteMode) — the single place that ever writes a field onto a
real profile asset. Kept for headless/test callers that only have the flat PrefetchPolicyCreator.Input
shape; CreatePrefetchPolicyWindow itself skips this DTO entirely and calls
CreateFromDrafts(IReadOnlyList<SerenityWizardScratchDraft<PrefetchPolicyProfile>>, string, string, bool, UnboundRowWriteMode) with its own per-row SerenityWizardScratchDraft<PrefetchPolicyProfile>
drafts directly.
Declaration
public static PrefetchPolicyCreator.Result Create(PrefetchPolicyCreator.Input input)
Parameters
| Type | Name | Description |
|---|---|---|
| PrefetchPolicyCreator.Input | input |
Returns
| Type | Description |
|---|---|
| PrefetchPolicyCreator.Result |
CreateFromDrafts(IReadOnlyList<SerenityWizardScratchDraft<PrefetchPolicyProfile>>, string, string, bool, UnboundRowWriteMode)
The single write path: resolves each row's profile asset, then the PrefetchPolicyRegistry itself, then commits every field on each draft onto its resolved profile via Serenity.Global.Infrastructure.Editor.SerenityWizardScratchDraft`1.CopyOnto(`0,`0) — serialization decides what gets written, not a hand-maintained field list. On any failure — including the pre-flight refusal below — every mutation is rolled back through the transaction's existing-asset restores, or nothing is ever written at all when the refusal fires before the transaction begins. Each row's own CALLER-OWNED draft — a long-lived window row for CreatePrefetchPolicyWindow — is captured via Serenity.Global.Infrastructure.Editor.SerenityExistingAssetRestore before its Id trim, and restored on failure, so the window's own rows are left exactly as the author had them typed.
A row's own Serenity.Global.Infrastructure.Editor.SerenityWizardScratchDraft`1.SourceAsset is the write target when
set — never an Id lookup. A row seeded from an existing profile (CreatePrefetchPolicyWindow's
own FromExisting rows) stays bound to that SAME asset regardless of what the author retypes its
Id field to: an Id edit on a seeded row renames that one asset, it never re-targets the write onto
whatever a DIFFERENT existing profile the new Id string happens to match — retyping the Id never
resolves-and-overwrites that OTHER asset, so the original stays in the registry untouched. Only a
row with no source (Serenity.Global.Infrastructure.Editor.SerenityWizardScratchDraft`1.CreateNew — a genuinely new row,
or every row Create(Input) builds from the flat PrefetchPolicyCreator.Input DTO, which carries no
"seeded from" concept of its own) resolves by Id-in-folder, exactly as it always has.
Defense in depth: a bound row can never touch another asset by construction, but an UNBOUND
row resolving by Id could still collide with an asset a DIFFERENT row in the same batch already owns
as its own source — the exact shape the caller-side wizard validation
(CreatePrefetchPolicyWindow's ValidateRowBindings, built on
ValidateRowIdNotBoundToADifferentAsset(IReadOnlyDictionary<string, PrefetchPolicyProfile>, string, string)) exists to catch before
this ever runs. This method does not simply trust that: Serenity.AssetPrefetcher.Infrastructure.Editor.Builder.PrefetchPolicyCreator.ValidateNoUnboundRowClaimsAnotherRowsSource(System.Collections.Generic.IReadOnlyList{Serenity.Global.Infrastructure.Editor.SerenityWizardScratchDraft{Serenity.AssetPrefetcher.Infrastructure.Settings.PrefetchPolicyProfile}},System.String)
re-checks it independently, before the transaction opens, so a caller-side validation gap can never
turn into a written file.
Create-only, at the write boundary: the WINDOW's own row-binding validation reads a cached
folder scan that nothing invalidates when the UnityEditor.AssetDatabase changes externally between
recomputes — a fresher cache narrows that window but can never close it. unboundRowWriteMode
closes it here instead: with CreateOnly,
Serenity.AssetPrefetcher.Infrastructure.Editor.Builder.PrefetchPolicyCreator.ValidateUnboundRowsAreCreateOnly(System.Collections.Generic.IReadOnlyList{Serenity.Global.Infrastructure.Editor.SerenityWizardScratchDraft{Serenity.AssetPrefetcher.Infrastructure.Settings.PrefetchPolicyProfile}},System.String) re-resolves every unbound row's Id against disk one
more time, independent of whatever the caller already checked, and refuses before the transaction
opens when it matches ANY existing profile — not only one owned by another row in this batch.
Declaration
public static PrefetchPolicyCreator.Result CreateFromDrafts(IReadOnlyList<SerenityWizardScratchDraft<PrefetchPolicyProfile>> profileDrafts, string registryAssetPath, string profilesFolderPath, bool registerAsAddressables, PrefetchPolicyCreator.UnboundRowWriteMode unboundRowWriteMode)
Parameters
| Type | Name | Description |
|---|---|---|
| IReadOnlyList<SerenityWizardScratchDraft<PrefetchPolicyProfile>> | profileDrafts | Every profile row to write, already resolved (an already-seeded scratch draft from an existing profile for an update-in-place row, or a freshly populated one for a new row). Each draft's own Guid is ignored on purpose — this method owns identity via Serenity.Global.Infrastructure.Editor.SerenityWizardScratchDraft`1.EnsureIdentity(`0,`0). |
| string | registryAssetPath | Explicit registry asset path — see RegistryAssetPath. |
| string | profilesFolderPath | Folder new profile assets are created under, and searched for an existing same-Id asset to update in place. Also the fallback folder for a brand-new registry asset. |
| bool | registerAsAddressables | Whether to register newly created assets as Addressable. |
| PrefetchPolicyCreator.UnboundRowWriteMode | unboundRowWriteMode | How an unbound row's Id-in-folder resolution is allowed to behave. No default on purpose — every caller states its own intent explicitly: Create(Input) passes the documented headless UpdateExistingById behavior; CreatePrefetchPolicyWindow passes CreateOnly. |
Returns
| Type | Description |
|---|---|
| PrefetchPolicyCreator.Result |
PlannedProfilePath(string, string)
Where a NEW profile with id is created in profilesFolderPath.
Declaration
public static string PlannedProfilePath(string profilesFolderPath, string id)
Parameters
| Type | Name | Description |
|---|---|---|
| string | profilesFolderPath | |
| string | id |
Returns
| Type | Description |
|---|---|
| string |
Preview(Input)
Computes what Create(Input) would do without mutating the project — the same resolution helpers, read-only.
Declaration
public static PrefetchPolicyCreator.PreviewResult Preview(PrefetchPolicyCreator.Input input)
Parameters
| Type | Name | Description |
|---|---|---|
| PrefetchPolicyCreator.Input | input |
Returns
| Type | Description |
|---|---|
| PrefetchPolicyCreator.PreviewResult |
ResolveRegistryContext(string)
Thin wrapper over the shared ResolveSettingsContext<TSettings>(string, string), exposed so CreatePrefetchPolicyWindow can auto-detect the project-wide singleton for its "Edit existing" field. A second (or later) PrefetchPolicyRegistry asset does not break anything at runtime — the composition root's serialized field is assigned by hand, not discovered — so ambiguity here is surfaced as a warning (see Validate(Input)), never a hard error.
Declaration
public static SettingsAssetAuthoring.SettingsResolution<PrefetchPolicyRegistry> ResolveRegistryContext(string explicitRegistryAssetPath = "")
Parameters
| Type | Name | Description |
|---|---|---|
| string | explicitRegistryAssetPath |
Returns
| Type | Description |
|---|---|
| SettingsResolution<PrefetchPolicyRegistry> |
Validate(Input)
Thin forward to Validate(Input) — kept here so existing
callers of PrefetchPolicyCreator.Validate (headless/test call sites) do not need to know the
validation family moved to its own collaborator.
Declaration
public static SerenityCreationValidationResult Validate(PrefetchPolicyCreator.Input input)
Parameters
| Type | Name | Description |
|---|---|---|
| PrefetchPolicyCreator.Input | input |
Returns
| Type | Description |
|---|---|
| SerenityCreationValidationResult |