Version: Unity 6.7 Beta (6000.7)
Language : English
Create a file table provider for text files
Localization settings reference

Create a custom asset provider

Load localized content from a place the built-in sources can’t reach.

This example serves localized tables from an AssetBundle in StreamingAssets, so localized content can ship and update separately from the Player. For example, you can use this structure to create downloadable content or mods for your application.

A custom source has two halves. The runtime provider loads by address, and a companion class in the Unity Editor records what the provider serves when you assign a collection to it. For details on how sources resolve requests, refer to Content sources.

Prerequisites

Before you start, make sure you have the following:

Create the provider

The runtime side implements IAssetProvider plus the loading capabilities it supports: ISynchronousAssetProvider, IAsyncAssetProvider, or both. Requests arrive as an AssetKey that carries an address and an expected type. The provider answers the addresses it recognizes and declines the rest, so the next source in the chain can serve them.

[Serializable]
public class AssetBundleAssetProvider : IAssetProvider, IAsyncAssetProvider, ISynchronousAssetProvider
{
    [SerializeField] string m_BundleName = "localization";

    // The addresses this provider serves. The editor half fills the list when a collection is assigned.
    [SerializeField, HideInInspector] List<string> m_Addresses = new();

    AssetBundle m_Bundle;

    AssetBundle Bundle
    {
        get
        {
            if (m_Bundle == null)
                m_Bundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, m_BundleName));
            return m_Bundle;
        }
    }

    public void AddAddress(string address)
    {
        if (!string.IsNullOrEmpty(address) && !m_Addresses.Contains(address))
            m_Addresses.Add(address);
    }

    public void RemoveAddress(string address) => m_Addresses.Remove(address);

    public void ClearAddresses() => m_Addresses.Clear();

    public bool TryLoadAsset<T>(AssetKey key, out T asset) where T : Object
    {
        asset = m_Addresses.Contains(key.Address) && Bundle != null
            ? Bundle.LoadAsset(key.Address, key.Type) as T
            : null;
        return asset != null;
    }

    public async Awaitable<T> LoadAssetAsync<T>(AssetKey key, CancellationToken cancellationToken) where T : Object
    {
        if (!m_Addresses.Contains(key.Address) || Bundle == null)
            return null;
        var request = Bundle.LoadAssetAsync(key.Address, key.Type);
        await request;
        cancellationToken.ThrowIfCancellationRequested();
        return request.asset as T;
    }

    public void Release(Object asset)
    {
        // Assets unload with the bundle, so there is nothing to release per asset.
    }
}

Create the Editor companion

When you assign a collection to a source, the Editor asks the source’s companion to register the collection’s content. This companion records each table’s address on the provider. The addresses follow the {collectionName}_{localeCode} convention the base class provides.

[AssetProviderEditor(typeof(AssetBundleAssetProvider))]
public class AssetBundleAssetProviderEditor : AssetProviderEditor
{
    protected override void RegisterTable(IAssetProvider provider, ResourceTableCollection collection, ResourceTable table)
    {
        // Record the table's address so the runtime serves it from the bundle.
        // The bundle must contain the table asset under the same name.
        ((AssetBundleAssetProvider)provider).AddAddress(TableAddress(collection, table));
    }

    protected override void UnregisterTable(IAssetProvider provider, ResourceTableCollection collection, ResourceTable table)
    {
        ((AssetBundleAssetProvider)provider).RemoveAddress(TableAddress(collection, table));
    }

    public override void ClearRegistrations(IAssetProvider provider)
    {
        ((AssetBundleAssetProvider)provider).ClearAddresses();
    }
}

Build the bundle

The provider expects the bundle to contain the collection’s table assets, resolvable by the same names it registered. Assign the collection’s table assets to an AssetBundle named localization, then build the AssetBundle into StreamingAssets. Refer to AssetBundles.

Use the source

To serve a collection from your provider:

  1. Open Edit > Project Settings > Localization and add Asset Bundle Asset Provider to the content sources.
  2. Select the table collection asset and assign it to the new source in the Inspector window.
  3. Enter Play mode. The tables now resolve from the bundle.

Additional resources

Create a file table provider for text files
Localization settings reference