com.xmobitea.changx.mini-config
v1.5.5
Published
ScriptableObject-based local and remote config abstractions for Unity.
Readme
XmobiTea Config
Small ScriptableObject-based config abstraction package for Unity.
AI-focused docs
Use these task-oriented files when you need the smallest possible context:
AGENTS.mdAI_QUICKSTART.mdAI_SETUP.mdAI_USAGE.mdAI_API_REFERENCE.mdAI_BEHAVIOR.md
This package does not fetch remote data for you. It only provides base types for:
- local config assets backed by serialized ScriptableObject fields;
- cached remote config data backed by
XmobiTea.MiniStoreRefs.StorePrefs; - combined local-plus-remote config assets that keep serialized local data and cached remote data side-by-side.
Public Types
ConfigDataItemAbstract config item base with a readonlyidproperty and a virtualOnUpdateDataDone()hook.LocalScriptableObjectConfigDataAbstract local config base withInit(),OnInit(), andOnUpdateDataDone().LocalConfigDataArray<TLocalItem>Abstract local list config withlocalItems,localCount, andFindLocal(...).LocalConfigDataObject<TLocalItem>Abstract local single-item config withlocalItem.RemoteScriptableObjectConfigDataAbstract remote config base withremoteConfigName,remoteVersion,Init(), andUpdateConfig(...).RemoteConfigDataArray<TRemoteItem>Abstract remote list config backed by JSON plusStorePrefs.RemoteConfigDataObject<TRemoteItem>Abstract remote single-item config backed by JSON plusStorePrefs.BothScriptableObjectConfigDataAbstract combined-config base withremoteConfigName,remoteVersion,Init(),UpdateConfig(...),OnInit(), andOnUpdateDataDone().BothConfigDataArray<TLocalItem, TRemoteItem>Abstract local-plus-remote list config with serialized local items, cached remote items, lookup helpers, tuple lookup by id, and JSON export.BothConfigDataObject<TLocalItem, TRemoteItem>Abstract local-plus-remote object config with a serialized local item, cached remote item, update handling, and JSON export.
Exact Behavior
ConfigDataItem
- The private
_idfield is serialized by Unity and mapped from JSON through[JsonProperty("id")]. - The public
idgetter is marked with[JsonIgnore]. OnUpdateDataDone()does nothing by default.
Local Configs
LocalScriptableObjectConfigData.Init() always runs this sequence:
OnInit()OnUpdateDataDone()
The local base class does not read JSON, write prefs, or persist anything by itself.
LocalConfigDataArray<TLocalItem>:
- Stores data in the serialized
_localItemslist already present on the asset. - Exposes
localItems,localCount,FindLocal(int id), andFindLocal(Predicate<TLocalItem>). localCountdirectly returns_localItems.Count.OnUpdateDataDone()callsOnUpdateDataDone()on every item in_localItems.
LocalConfigDataObject<TLocalItem>:
- Stores data in the serialized
_localItemalready present on the asset. - Exposes
localItem. OnUpdateDataDone()calls_localItem.OnUpdateDataDone().
Remote Configs
RemoteScriptableObjectConfigData stores two serialized fields:
remoteConfigName: used as theStorePrefskey namespace._remoteVersion: the in-memory version exposed through the readonlyremoteVersionproperty.
Exact StorePrefs keys:
ConfigData_{remoteConfigName}_remoteversion
ConfigData_{remoteConfigName}_remotedataRemoteScriptableObjectConfigData.Init() behaves like this:
- Read the stored remote version from
StorePrefs. - If the serialized asset remote version is greater than or equal to the stored remote version, skip
OnInit(), runOnUpdateDataDone(), keep the asset's embedded data, and return. - If the stored remote version is greater, run
OnInit()to load cached state. - Run
OnUpdateDataDone().
For the built-in remote object and array types, this means cached JSON is only loaded during Init() when the stored remote version is greater than the serialized asset remote version.
RemoteScriptableObjectConfigData.UpdateConfig(int version, string configJson):
- updates
_remoteVersion; - writes the version to
StorePrefs; - does not read
configJson; - does not call
StorePrefs.Save().
RemoteConfigDataArray<TRemoteItem>:
- Exposes
remoteItems,remoteCount,FindRemote(int id), andFindRemote(Predicate<TRemoteItem>). OnInit()deserializesStorePrefs.GetString(..., "[]")into_remoteItems.UpdateConfig(...)deserializes the incoming JSON array into_remoteItems.UpdateConfig(...)stores the raw JSON string inStorePrefs.UpdateConfig(...)callsOnUpdateDataDone()on every item in_remoteItems.
RemoteConfigDataObject<TRemoteItem>:
- Exposes
remoteItem. OnInit()deserializesStorePrefs.GetString(..., "{}")into_remoteItem.UpdateConfig(...)deserializes the incoming JSON object into_remoteItem.UpdateConfig(...)stores the raw JSON string inStorePrefs.UpdateConfig(...)calls_remoteItem.OnUpdateDataDone().
Both Configs
BothScriptableObjectConfigData stores two serialized fields:
remoteConfigName: used as theStorePrefskey namespace._remoteVersion: the in-memory version exposed through the readonlyremoteVersionproperty.
It uses the same StorePrefs keys as RemoteScriptableObjectConfigData:
ConfigData_{remoteConfigName}_remoteversion
ConfigData_{remoteConfigName}_remotedataBothScriptableObjectConfigData.Init() behaves like this:
- Read the stored remote version from
StorePrefs. - If the serialized asset remote version is greater than or equal to the stored remote version, skip
OnInit(), runOnUpdateDataDone(), keep the asset's embedded data, and return. - If the stored remote version is greater, run
OnInit()to load cached remote state. - Run
OnUpdateDataDone().
BothScriptableObjectConfigData.UpdateConfig(int version, string configJson):
- updates
_remoteVersion; - writes the version to
StorePrefs; - leaves JSON parsing and raw JSON persistence to derived classes.
BothConfigDataArray<TLocalItem, TRemoteItem>:
- Stores serialized
_localItemsand_remoteItemslists directly on the asset. - Exposes
localItems,remoteItems,localCount,remoteCount,FindLocal(...),FindRemote(...), andFind(int id). Find(int id)returns a tuple in the shape(localItem, remoteItem).OnInit()deserializesStorePrefs.GetString(..., "[]")into_remoteItemswhen the cached remote version is newer than the serialized asset version.OnUpdateDataDone()callsOnUpdateDataDone()on every item in both lists.UpdateConfig(...)deserializes the incoming JSON array into_remoteItems, stores the raw JSON inStorePrefs, and callsOnUpdateDataDone()on every remote item.ToJson()exports the current remote version and remote items in the shape{ "version": ..., "config": ... }.
BothConfigDataObject<TLocalItem, TRemoteItem>:
- Stores serialized
_localItemand_remoteItemvalues directly on the asset. - Exposes
localItemandremoteItem. OnInit()deserializesStorePrefs.GetString(..., "{}")into_remoteItemwhen the cached remote version is newer than the serialized asset version.OnUpdateDataDone()callsOnUpdateDataDone()on both items.UpdateConfig(...)deserializes the incoming JSON object into_remoteItem, stores the raw JSON inStorePrefs, and callsOnUpdateDataDone()on the remote item.ToJson()exports the current remote version and remote item in the shape{ "version": ..., "config": ... }.
Migration Note
Earlier remote versions used these keys:
ConfigData_{configName}_version
ConfigData_{configName}_dataThe current runtime no longer reads those keys. Existing cached remote data must be migrated to the new _remoteversion and _remotedata keys or refreshed from the server after upgrade.
Concrete Subclass Pattern
Unity asset workflows cannot create assets directly from these abstract open generic base types, so project code should wrap them in concrete subclasses.
You must create concrete subclasses for:
LocalConfigDataArray<TLocalItem>LocalConfigDataObject<TLocalItem>RemoteConfigDataArray<TRemoteItem>RemoteConfigDataObject<TRemoteItem>BothConfigDataArray<TLocalItem, TRemoteItem>BothConfigDataObject<TLocalItem, TRemoteItem>
using System;
using Newtonsoft.Json;
using UnityEngine;
using XmobiTea.MiniConfig;
[Serializable]
public sealed class EnemyConfigItem : ConfigDataItem
{
[JsonProperty("hp")]
[SerializeField] private int _hp;
public int hp => _hp;
}
[CreateAssetMenu(fileName = "EnemyLocalConfig", menuName = "XmobiTea Config/Enemy Local Config")]
public sealed class EnemyLocalConfig : LocalConfigDataArray<EnemyConfigItem>
{
}
[CreateAssetMenu(fileName = "EnemyRemoteConfig", menuName = "XmobiTea Config/Enemy Remote Config")]
public sealed class EnemyRemoteConfig : RemoteConfigDataArray<EnemyConfigItem>
{
}
[CreateAssetMenu(fileName = "EnemyBothConfig", menuName = "XmobiTea Config/Enemy Both Config")]
public sealed class EnemyBothConfig : BothConfigDataArray<EnemyConfigItem, EnemyConfigItem>
{
}Usage Example
using UnityEngine;
using XmobiTea.MiniStoreRefs;
public sealed class ConfigBootstrap : MonoBehaviour
{
[SerializeField] private EnemyLocalConfig enemyLocalConfig;
[SerializeField] private EnemyRemoteConfig enemyRemoteConfig;
[SerializeField] private EnemyBothConfig enemyBothConfig;
private void Awake()
{
enemyLocalConfig.Init();
enemyRemoteConfig.Init();
enemyBothConfig.Init();
}
public void ApplyRemoteJson(int version, string json)
{
enemyBothConfig.UpdateConfig(version, json);
StorePrefs.Save();
}
}BothConfigDataArray and BothConfigDataObject are standalone combined config assets. They do not read from separate local or remote child assets.
Call enemyBothConfig.Init() before runtime reads so item hooks run and newer cached remote data can replace the serialized remote snapshot.
Constraints And Runtime Assumptions
- This package does not include networking, download, retry, merge, or remote version-check logic.
LocalConfigDataArray<TLocalItem>,LocalConfigDataObject<TLocalItem>,RemoteConfigDataArray<TRemoteItem>,RemoteConfigDataObject<TRemoteItem>,BothConfigDataArray<TLocalItem, TRemoteItem>, andBothConfigDataObject<TLocalItem, TRemoteItem>are abstract.- The list/object containers do not contain null guards for
_localItems,_localItem,_remoteItems,_remoteItem, or individual entries. - Invalid or shape-mismatched JSON can cause deserialization to return
null, which may later cause aNullReferenceExceptionduringOnUpdateDataDone(),localCount,remoteCount,FindLocal(...),FindRemote(...), or directlocalItem/remoteItemaccess throughBoth*. - Remote object configs expect JSON object payloads. Remote array configs expect JSON array payloads.
- Remote updates are not flushed explicitly because
UpdateConfig(...)does not callStorePrefs.Save(). remoteConfigNamemust remain stable, otherwise the stored keys change.- Upgrading from the old
_versionand_datakeys does not migrate cached values automatically.
Namespace
using XmobiTea.MiniConfig;Package Metadata
- Package name:
com.xmobitea.changx.mini-config - Package version:
1.5.4 - Unity version:
2022.3+ - License:
Apache-2.0 - Runtime assembly:
com.xmobitea.changx.mini-config.runtime - Package dependencies:
com.xmobitea.changx.app,com.xmobitea.changx.mini-storeprefs - JSON serializer used by runtime and examples:
Newtonsoft.Json
