This page documents the recommended data-driven architecture used across Luna Systems:
ServiceLocator for runtime resolutionICatalog, IAssetCatalog<T>)CatalogKey fields for serializable referencesIDataSerializer/Newtonsoft for JSON serializationThe concrete example below uses Inventory sample assets/code from Packages/com.cupkekgames.luna/Samples~/Library, but the same pattern applies to other systems.
Inventory is the example model:
InventoryItemDefinitionSO : DataSO<InventoryItemDefinition>InventoryItemDefinition : IDataInventoryItemDefinition.IconKey : CatalogKeyInventoryItem.Key : CatalogKeyInventoryItemReference.ItemKey : CatalogKeyThis keeps references stable for JSON/saves and avoids direct hard references inside runtime data models.
IFeature on data models (e.g. InventoryItemDefinition.Features) is authored, static behavior/config: equip rules, tooltip layout, cooldown duration, etc.
Mutable data that belongs to a specific runtime instance (last use time, durability remaining, charges left) must not live on shared definitions. Use IFeatureStateData from the Data package and store a [SerializeReference] List<IFeatureStateData> on the runtime entity (for example InventoryItem).
IFeatureStateData.CloneState() for deep copy when cloning the owner (e.g. stack split).[SerializeField] for persisted values, [NonSerialized] for session-only fields (e.g. Time.time-based cooldown timestamps that should reset on load).ItemTooltipContext.Item.GetState<T>()), using definition fields for config and state fields for what changes at runtime.Example (inventory consumable): ConsumableFeature holds CooldownDuration on the definition; ConsumableCooldownState on the stack holds LastUsedTime.
Example (tier override): ItemTierFeature.Tier is the authored default; ItemTierRuntimeState.TierOverride on the stack overrides tooltip and slot USS when set (empty override falls back to the definition).
The same split applies to other systems (abilities, quests, etc.)—Inventory is not a special case in the architecture.
When serializing polymorphic lists with Newtonsoft and TypeNameHandling, register concrete IFeatureStateData types in your SerializationTypeProviderSO known-types list.
Sample constants:
InventoryConstants.ItemsCatalogId = "Items"InventoryConstants.IconsCatalogId = "ItemIcon"AssetCatalog<T> registers itself to ServiceLocator for:
ICatalog (key listing)IAssetCatalog (untyped value lookup)IAssetCatalog<T> (typed value lookup)All are keyed by catalog id and use append: true, so multiple catalog assets can contribute to one id.
From Luna Demo Service Registry Items.asset:
Item Provider Equipments.asset (_catalogId: Items)Item Provider Potions.asset (_catalogId: Items)ItemSpriteDatabase.asset (_catalogId: ItemIcon)ItemTypeKeyProvider.asset (_catalogId: ItemType)EquipmentTypeKeyProvider.asset (_catalogId: EquipmentType)ItemTierKeyProvider.asset (_catalogId: ItemTier)CupkekGames Data Serializer Registrar.asset (registers IDataSerializer)Result: definitions can be split across multiple catalogs while still resolving through one logical key space (Items).
InventoryItemDatabaseSO is the bridge that gameplay/UI code uses through IInventoryItemDatabase:
GetItemDefinition(CatalogKey) validates catalog id (defaults to Items if empty)ServiceLocator.GetAll<IAssetCatalog<InventoryItemDefinitionSO>>("Items")InventoryItemDefinitionSO.DataIAssetCatalog<Sprite> by IconKey.Catalog (fallback ItemIcon)This is why both Items and ItemIcon catalogs must be registered before inventory UI/gameplay runs.
DataSO<T> uses ServiceLocator.Get<IDataSerializer>() for:
ToJson()LoadFromJson()In samples, DataSerializerRegistrar registers NewtonsoftDataSerializer as IDataSerializer.
NewtonsoftDataSerializer also depends on ServiceLocator.Get<SerializationManager>().
So if you call DataSO JSON APIs at runtime, you must register a SerializationManager too (for example through SerializationManagerRegistrar in the Newtonsoft sample registry).
In short:
IDataSerializer + SerializationManagerTo apply this pattern in your own system:
IDataSerializer (for example via DataSerializerRegistrar)SerializationManager if using Newtonsoft JSON calls (ToJson, LoadFromJson, save/load)No IAssetCatalog<...> registered with key '...'
IAssetCatalog<...>('...') not found in ServiceLocator
SerializationManager must be initialized before use
IDataSerializer exists, but SerializationManager was not registered/initialized.Settings
Theme
Light
Contrast
Material
Dark
Dim
Material Dark
System
Sidebar(Light & Contrast only)
Font Family
DM Sans
Wix
Inclusive Sans
AR One Sans
Direction