Namespace Serenity.Global.Infrastructure.Utils
Classes
AudioMixerDependencyCache
Static cache for AudioMixer and AudioMixerGroup assets that keeps Addressables handles alive to prevent Unity from unloading these critical dependencies during the application lifecycle. This solves the issue where AudioMixerGroup references inside ScriptableObjects become "fake-null" when Addressables handles are released.
UnityAddressableUtils
Direct API to load ALL from Addressables (no filtering, no caching).
Prefer the unified API: LoadAllFromAnyBlocking<T>(string).
Every public entry point is gated by SerenityAssetLoadingModeProvider:
- In
ResourcesOnlymode the methods short-circuit and return an empty list without touching the Addressables API. A one-time verbose log explains the no-op so a caller that genuinely needed Addressables sees the divergence. - In Addressables-using modes the behaviour is unchanged; the blocking
variant additionally throws NotSupportedException on WebGL because
WaitForCompletioncannot be serviced there.
UnityAssetUtils
Utility class for Unity asset loading operations including Addressables management, audio clip caching, and asset warm-up functionality.
Threading contract: every Addressables call in this class runs on the Unity main
thread. Addressables mutates unsynchronized internal state (notably
AddressablesImpl.m_resultToHandle and the global operation-callback node cache)
from its completion callbacks, and WaitForCompletion drives those callbacks by
pumping the ResourceManager on the calling thread. A single Addressables call made from
a thread-pool thread — a Release in a continuation, or in a cancellation callback —
corrupts that state and surfaces as an IndexOutOfRangeException or NullReferenceException
raised (and swallowed) inside Addressables' own callback dispatch.
This is why every await below uses ConfigureAwait(true): the continuation
must resume through the captured Unity SynchronizationContext. Addressables
completes its Task with
RunContinuationsAsynchronously,
so ConfigureAwait(false) does not merely *allow* a pool thread — it guarantees one.
For the same reason no cancellation callback releases a handle: those callbacks run on
whichever thread requested cancellation. Handles are released on the post-await path
instead, which costs nothing because Addressables cannot abort an in-flight load anyway.
Every public entry point is gated by SerenityAssetLoadingModeProvider:
AddressablesWithResourcesFallback(default) keeps the committed behaviour: Addressables first, Resources fallback.AddressablesOnlyskips every Resources fallback path.ResourcesOnlynever touches the Addressables API — noLoadAssetAsync, noLoadAssetsAsync, noLoadResourceLocationsAsync, noWaitForCompletion.
In ResourcesOnly mode the synchronous WebGL guard is moot: no sync Addressables call is reachable. The guard remains on the Addressables-using branches so that any AddressablesOnly / AddressablesWithResourcesFallback caller that hits sync code on WebGL still throws NotSupportedException with an actionable message.
UnityAudioMixerGroupUtils
Utility class for AudioMixerGroup operations
UnityCollectionSettingsLoader
Loads every settings asset an installer needs for a module label, applying the adopted-twin rule (CollectionSettingsSelection): once a project owns the clone made from a shipped asset, the shipped original is dropped instead of being installed beside it. Without it an adopted project registers two of everything a collection holds — two music services, two menu definitions, two of each modal — because LoadAllFromAnyBlocking<T>(IEnumerable<string>) returns both and the caller keeps both.
The collection counterpart of UnitySingletonSettingsLoader, and kept beside it rather
than added to UnityAssetUtils.cs for the same reason: that file is already at the file-size
ratchet.
Partial adoption keeps working: a shipped member with no adopted twin is untouched, so a project that adopted only some of a collection installs its own clones plus the shipped remainder.
UnityHierarchyUtils
Helpers for navigating and querying the Unity scene hierarchy
UnityMainThread
Unity MonoBehaviour singleton for managing cross-thread operations and main thread dispatching.
Provides thread-safe methods to execute actions and functions on Unity's main thread from background threads,
with automatic bootstrap initialization and concurrent queue-based operation management.
UnityObjectUtils
Small, generalized helpers for Unity object identity checks and component lookup, factored out of the
per-service copies that used to hand-roll them (e.g. the destroyed-object-aware null check that used
to live only in UnityAssetPrefetcherService).
UnityParserUtils
Helpers to parse objects to specific Unity types with error handling
UnityResourceUtils
Direct API to load ALL from Resources (no filtering, no async, no caching).
Prefer the unified API: LoadAllFromAnyBlocking<T>(string)
UnityServiceHost
The "create a GameObject, name it, add the hosting component" boilerplate repeated by every Unity
service factory (see UnityTimerServiceFactory, UnitySoundMixerServiceFactory,
UnityLocalizationServiceFactory, and the rest). Deliberately does NOT call
Object.DontDestroyOnLoad — factories differ on whether the service GameObject should survive a
scene load, so that call stays at each call site rather than being folded in here.
UnitySingletonSettingsLoader
Loads the single settings asset an installer needs for a module label, applying the
project-ownership rule: a project-owned settings asset beats a shipped one with the same
Id (SingletonSettingsSelection). Replaces the historical
candidates.Length > 0 ? candidates[0] : null idiom, which picked whichever asset
Addressables/Resources happened to enumerate first.
In SerenityAssetLoadingMode.ResourcesOnly, LoadAllFromAnyBlocking<T>(string)
ignores labels entirely (Resources.LoadAll has no label concept) and returns every asset
of type T under a Resources/ folder. Since Serenity never ships its
own settings under Assets/Serenity/Resources (see the "AutoLoad" warning on
LoadAllFromAnyBlocking<T>(string)), every candidate found this way is
project content by construction, so the module-label query and the
PROJECT_OWNED query return the same set and ownership resolves correctly
with no special-casing.
UnityTextMeasurementUtils
Measurement helpers for TextMeshPro texts, shared by every module that sizes rects around TMP labels.
UnityUiUtils
Helpers for Unity UI (uGUI) operations
UnityUserSystemUtils
Helpers to detect user system platform (desktop, mobile, consoles, web)
UnityYamlUtils
Utility class for parsing YAML content
WiredOrDiscoveredSettings
The two-tier rule every system's settings lookup follows: the reference a designer wired on the composition root wins, and label discovery is the fallback for a project that wired nothing.