npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.md
  • AI_QUICKSTART.md
  • AI_SETUP.md
  • AI_USAGE.md
  • AI_API_REFERENCE.md
  • AI_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

  • ConfigDataItem Abstract config item base with a readonly id property and a virtual OnUpdateDataDone() hook.
  • LocalScriptableObjectConfigData Abstract local config base with Init(), OnInit(), and OnUpdateDataDone().
  • LocalConfigDataArray<TLocalItem> Abstract local list config with localItems, localCount, and FindLocal(...).
  • LocalConfigDataObject<TLocalItem> Abstract local single-item config with localItem.
  • RemoteScriptableObjectConfigData Abstract remote config base with remoteConfigName, remoteVersion, Init(), and UpdateConfig(...).
  • RemoteConfigDataArray<TRemoteItem> Abstract remote list config backed by JSON plus StorePrefs.
  • RemoteConfigDataObject<TRemoteItem> Abstract remote single-item config backed by JSON plus StorePrefs.
  • BothScriptableObjectConfigData Abstract combined-config base with remoteConfigName, remoteVersion, Init(), UpdateConfig(...), OnInit(), and OnUpdateDataDone().
  • 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 _id field is serialized by Unity and mapped from JSON through [JsonProperty("id")].
  • The public id getter is marked with [JsonIgnore].
  • OnUpdateDataDone() does nothing by default.

Local Configs

LocalScriptableObjectConfigData.Init() always runs this sequence:

  1. OnInit()
  2. OnUpdateDataDone()

The local base class does not read JSON, write prefs, or persist anything by itself.

LocalConfigDataArray<TLocalItem>:

  • Stores data in the serialized _localItems list already present on the asset.
  • Exposes localItems, localCount, FindLocal(int id), and FindLocal(Predicate<TLocalItem>).
  • localCount directly returns _localItems.Count.
  • OnUpdateDataDone() calls OnUpdateDataDone() on every item in _localItems.

LocalConfigDataObject<TLocalItem>:

  • Stores data in the serialized _localItem already present on the asset.
  • Exposes localItem.
  • OnUpdateDataDone() calls _localItem.OnUpdateDataDone().

Remote Configs

RemoteScriptableObjectConfigData stores two serialized fields:

  • remoteConfigName: used as the StorePrefs key namespace.
  • _remoteVersion: the in-memory version exposed through the readonly remoteVersion property.

Exact StorePrefs keys:

ConfigData_{remoteConfigName}_remoteversion
ConfigData_{remoteConfigName}_remotedata

RemoteScriptableObjectConfigData.Init() behaves like this:

  1. Read the stored remote version from StorePrefs.
  2. If the serialized asset remote version is greater than or equal to the stored remote version, skip OnInit(), run OnUpdateDataDone(), keep the asset's embedded data, and return.
  3. If the stored remote version is greater, run OnInit() to load cached state.
  4. 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), and FindRemote(Predicate<TRemoteItem>).
  • OnInit() deserializes StorePrefs.GetString(..., "[]") into _remoteItems.
  • UpdateConfig(...) deserializes the incoming JSON array into _remoteItems.
  • UpdateConfig(...) stores the raw JSON string in StorePrefs.
  • UpdateConfig(...) calls OnUpdateDataDone() on every item in _remoteItems.

RemoteConfigDataObject<TRemoteItem>:

  • Exposes remoteItem.
  • OnInit() deserializes StorePrefs.GetString(..., "{}") into _remoteItem.
  • UpdateConfig(...) deserializes the incoming JSON object into _remoteItem.
  • UpdateConfig(...) stores the raw JSON string in StorePrefs.
  • UpdateConfig(...) calls _remoteItem.OnUpdateDataDone().

Both Configs

BothScriptableObjectConfigData stores two serialized fields:

  • remoteConfigName: used as the StorePrefs key namespace.
  • _remoteVersion: the in-memory version exposed through the readonly remoteVersion property.

It uses the same StorePrefs keys as RemoteScriptableObjectConfigData:

ConfigData_{remoteConfigName}_remoteversion
ConfigData_{remoteConfigName}_remotedata

BothScriptableObjectConfigData.Init() behaves like this:

  1. Read the stored remote version from StorePrefs.
  2. If the serialized asset remote version is greater than or equal to the stored remote version, skip OnInit(), run OnUpdateDataDone(), keep the asset's embedded data, and return.
  3. If the stored remote version is greater, run OnInit() to load cached remote state.
  4. 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 _localItems and _remoteItems lists directly on the asset.
  • Exposes localItems, remoteItems, localCount, remoteCount, FindLocal(...), FindRemote(...), and Find(int id).
  • Find(int id) returns a tuple in the shape (localItem, remoteItem).
  • OnInit() deserializes StorePrefs.GetString(..., "[]") into _remoteItems when the cached remote version is newer than the serialized asset version.
  • OnUpdateDataDone() calls OnUpdateDataDone() on every item in both lists.
  • UpdateConfig(...) deserializes the incoming JSON array into _remoteItems, stores the raw JSON in StorePrefs, and calls OnUpdateDataDone() on every remote item.
  • ToJson() exports the current remote version and remote items in the shape { "version": ..., "config": ... }.

BothConfigDataObject<TLocalItem, TRemoteItem>:

  • Stores serialized _localItem and _remoteItem values directly on the asset.
  • Exposes localItem and remoteItem.
  • OnInit() deserializes StorePrefs.GetString(..., "{}") into _remoteItem when the cached remote version is newer than the serialized asset version.
  • OnUpdateDataDone() calls OnUpdateDataDone() on both items.
  • UpdateConfig(...) deserializes the incoming JSON object into _remoteItem, stores the raw JSON in StorePrefs, and calls OnUpdateDataDone() 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}_data

The 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>, and BothConfigDataObject<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 a NullReferenceException during OnUpdateDataDone(), localCount, remoteCount, FindLocal(...), FindRemote(...), or direct localItem/remoteItem access through Both*.
  • Remote object configs expect JSON object payloads. Remote array configs expect JSON array payloads.
  • Remote updates are not flushed explicitly because UpdateConfig(...) does not call StorePrefs.Save().
  • remoteConfigName must remain stable, otherwise the stored keys change.
  • Upgrading from the old _version and _data keys 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