Namespace Serenity.CreateGame.Infrastructure.Editor.Systems
Classes
InstallableSystemDependencyOrder
Pure, reflection-free level-ordered topological sort over a declared dependency graph of installable systems: level 0 holds every system with no prerequisites, and a system's level is one past the highest level among the systems it depends on. Within a level, systems are ordered bootstrap-first, then by SerenityInstallableSystemTier, then by display name (ordinal), so the result is a single deterministic sequence in which a system never precedes a prerequisite named in its own DependsOn. SerenityInstallableSystemCatalog resolves its reflection-discovered methods into InstallableSystemDependencyOrder.Nodes and hands them here; kept separate so the ordering rules are testable against a synthetic graph with no AppDomain scan involved.
PersistenceBackendDefinitionCreator
The Persistence row's Create action: builds a UnityPersistenceBackendDefinition asset — the
exact type UnitySerenityInstaller.PersistenceBackendDefinition consumes at boot — for a chosen
PersistenceBackendDefinitionOption, offered inline in the row rather than through a native
UnityEditor.GenericMenu (unusable headlessly, and blocks the editor's own IMGUI thread).
The created asset is registered Addressable under PERSISTENCE.
Every candidate installer type is named by string and resolved through ReflectionActivationUtils
/ UnityEditor.TypeCache — never by a compile-time typeof(...) — because this editor assembly
cannot (and must not) reference the Persistence installation assemblies, exactly the constraint
InstallTaskAuthoring.InstallerTypeFullName documents for the initialization-pipeline task facade.
PersistenceBackendDefinitionCreator.Result
Outcome of a CreateDefinition(PersistenceBackendDefinitionOption, string, bool) call.
SerenityInstallableSystem
One Install*() method the "create a new game" flow can offer for selective installation,
resolved from a SerenityInstallableSystemAttribute
declaration by SerenityInstallableSystemCatalog. Immutable — a snapshot of the
attribute's data plus the method's discovery order.
SerenityInstallableSystemCatalog
Discovers every SerenityInstallableSystemAttribute-decorated Install*() method
across every loaded Serenity.* assembly, without a compile-time reference to
Serenity.Installation (the attribute is a self-contained data holder resolved by reflection
only), then orders them by their declared DependsOn
prerequisites so a system never precedes anything it requires. Cached after the first scan; call
Invalidate() to force a rescan, e.g. after a domain reload a test suite triggers
deliberately.
SerenityInstallableSystemSelection
The set of SerenityInstallableSystem a wizard's user has opted into, tracked by InstallMethodName so it survives a domain reload as serialized window state. A system that InstallsAtBootstrap is always reported selected, regardless of what this selection explicitly holds, and a selected system's own DependsOn closure is never allowed to fall out of the selection while something else still needs it (see Select(SerenityInstallableSystem, IReadOnlyList<SerenityInstallableSystem>) and CanDeselect(SerenityInstallableSystem, IReadOnlyList<SerenityInstallableSystem>)).
SerenitySystemConfigurationFreshnessWatcher
Keeps a SerenitySystemConfigurationResolver honest about project changes the caller did
not itself cause: a reader who leaves a Hub view or wizard window open, authors a settings asset
through an external tool, and returns finds the resolver's cache invalidated automatically instead of
only on the next manual Refresh. Subscribes to UnityEditor.EditorApplication.projectChanged by
default, mirroring InstallableSystemSettingsResolutionCache's subscription; the subscribe and
unsubscribe delegates are injectable so a test can raise a change without touching the real editor
event.
SerenitySystemConfigurationResolver
Resolves where each SerenityInstallableSystem's settings asset currently stands:
missing, shipped inside the package, authored in the user's project, or invalid (ambiguous, or
carrying a broken IFoundationSettings identity). Cached until Invalidate() is
called — a caller that wants a fresh read after the project changed (e.g. a wizard window
regaining focus, following the LeaderboardWizardBoardStepValidationCache precedent)
invalidates first.
SerenitySystemConfigurationRow
One SerenitySystemConfigurationResolver result: a system paired with where its settings asset currently stands.
SettingsReferenceInspector
Walks a settings asset's serialized object-reference properties looking for one whose declared field
type accepts another catalog system's settings type (SettingsReferenceRules) but holds no
value — either never configured, or dangling (objectReferenceInstanceIDValue != 0 with a null
resolved value, IsDangling) — and assigns a replacement
once a sole project-owned candidate exists.
SettingsReferenceRules
The pure decision behind SettingsReferenceInspector: whether a settings field's declared
type is a reference to another catalog system's settings type, and the message a row shows when that
reference is unassigned. No UnityEditor access, so it is testable without any asset on disk.
SettingsRowReferenceAuditor
Post-pass applied after Resolve(IReadOnlyList<SerenityInstallableSystem>), run only against a project-owned singleton row (InProject, never InPackage — a shipped asset's unassigned reference falls back to the factory default, which is not a user misconfiguration to flag). A field declared to reference another catalog system's settings type (SettingsReferenceInspector) that was never configured keeps the row InProject with a warning detail and an offered Assign action; one found dangling (assigned once, now broken) downgrades the row to Invalid instead, since a sole remaining candidate cannot stand in for whatever the field used to point at. Kept as a separate collaborator so SerenitySystemConfigurationResolver itself stays about singleton/identity resolution only. A Collection row is skipped in this iteration — its AssetPath names only the first of possibly many members, so a single-asset reference walk cannot speak for the whole collection yet.
SettingsRowUnassignedReference
One serialized property on a resolved settings asset, declared to reference another catalog system's settings type, that SettingsReferenceInspector found either unassigned (never configured) or dangling (assigned once, now broken) — surfaced on a SerenitySystemConfigurationRow by SettingsRowReferenceAuditor. Only IsDangling false offers an Assign action; a dangling reference needs the row to go Invalid instead, since a sole candidate cannot tell whether it is the SAME asset the field used to point at.
ShippedSystemAssetCatalog
Every shipped package asset that belongs to one installable system, per
IsMemberOf(string, IReadOnlyCollection<string>, string, IReadOnlyList<string>, IReadOnlyList<(string PathContains, string Label)>). Scans every asset under
Serenity.Global.Infrastructure.Editor.SerenityEditorPaths.PackageRoots once (AssetDatabase.FindAssets(string.Empty, ...)),
and decides each one's labels the same way a real Retag All would need to: the union of
Serenity.Global.Infrastructure.Editor.Utils.UnityAddressablesLabeler.DecideLabels(System.String) (path/type folder rules) and
Serenity.Global.Infrastructure.Editor.Utils.SerenityAddressablesAutoLabeler.ResolveLabelsForType(System.Type) (the import-time auto-labeler's type
decision) — a path-only view misses both a composite view under Media/GeneratedViews and a
namespace-fallback ScriptableObject, which only carry a label through the second. Memoizes the result
behind Invalidate() so asking for several systems' member lists in the same wizard pass
costs one scan, not one per system.
ShippedSystemAssetMembershipRules
The pure decision behind ShippedSystemAssetCatalog: which shipped package asset belongs
to which installable system. An asset's Addressables labels alone are not enough — a theme's UI
component prefab (a Leaderboard row widget, say) carries both module:ui and module:leaderboard
(the latter from the shipped Components/Leaderboard.prefab layout path), but it lives under the Ui theme folder and ships/updates
with Ui, not Leaderboard. ResolvePrimaryOwnerLabel(string, IReadOnlyList<string>, IReadOnlyList<(string PathContains, string Label)>) answers that by folder position alone:
the label of the module whose folder segment sits directly under a package root's Media/ — the
"primary owner" a label-only view cannot see. No AssetDatabase calls anywhere here, so this is
testable with hand-written paths and labels.
SystemBootTaskWiring
One SystemBootTaskWiringInspector result: whether a system's install task is wired into a
project-owned UnityInitializationPipelineProfile, and which profile(s) when it is.
SystemBootTaskWiringInspector
Resolves, for each of a set of systems, whether its install task already sits in some project-owned
UnityInitializationPipelineProfile — the same question the Systems and Settings steps both need
answered, so a fresh project shows a system's row as "wired" instead of just "Missing" when its shipped
profile already installs it. Delegates the actual profile scan to
Serenity.Global.Infrastructure.Editor.InitializationPipeline.InstallTaskAuthoring.ProjectOwnedProfilePathsByInstallMethodName(System.Collections.Generic.IReadOnlyCollection{System.String},System.Collections.Generic.IReadOnlyList{System.String})
so this module never needs a typed reference to UnityInitializationPipelineProfile itself.
Structs
InstallableSystemDependencyOrder.Node
One system's ordering-relevant data — a reflection-free projection of a SerenityInstallableSystemAttribute declaration.
PersistenceBackendDefinitionOption
One selectable kind the Persistence row's in-window Create action offers: a concrete
Serenity.Persistence.Installation.Installers.PersistenceInstaller subclass — a built-in one
Serenity ships, or a custom one a project generated (e.g. through Service Extension Creator's
InfrastructureSubclass style) — described for the reader and carrying whatever constructor arguments
UnityPersistenceBackendActivator needs to build it, so the created
Serenity.Global.Infrastructure.Settings.UnityPersistenceBackendDefinition asset activates without
the reader ever typing a type name or an argument list by hand. Named by string, never by
Type: this option is built inside the Create Game editor assembly, which cannot
(and must not) reference the Persistence installation assemblies — the same constraint
InstallTaskAuthoring.InstallerTypeFullName documents for the initialization-pipeline task facade.
Enums
SerenitySystemConfigurationState
Where a SerenityInstallableSystem's settings asset currently stands, as resolved by SerenitySystemConfigurationResolver.
SystemBootTaskWiringKind
Whether a system's initialization-pipeline install task is already wired into a project-owned
UnityInitializationPipelineProfile, as resolved by SystemBootTaskWiringInspector.