Tutorial 9 - Set Data in Editor Using Script Assets

Summary

Use script assets to store configurable data as an asset, similar to Unity's scriptable objects.

Requirements

Setup

Create a Room

Scripting

Create a Script Asset

Script assets are scripts that can store data saved as assets and be loaded on the server or client. Proxy scripts that inherit from ScriptableObject are generated for script assets so they can be saved in Unity as scriptable objects, similar to how proxy scripts that inherit from Monobehaviour are generated for server scripts.

Our script asset will store a dictionary mapping strings to int values, and will have a function for logging the contents of the dictionary.

CommonAsset.cs

using System.Collections.Generic;
using KS.Reactor;

// This attribute keeps the proxy data in builds so the asset can be loaded from the proxy in client builds.
[ksSharedData]
public class CommonAsset : ksScriptAsset
{
    [ksEditable]
    public Dictionary<string, int> Stats;

    // Log the stats from the dictionary.
    public void LogStats()
    {
        string str = "{";
        foreach (KeyValuePair<string, int> stat in Stats)
        {
            if (str.Length > 1)
            {
                str += ", ";
            }
            str += stat.Key + ": " + stat.Value;
        }
        str += "}";

        // Log the asset id and asset path.
        ksLog.Info("Id: " + AssetId + ", Path: " + AssetPath);

        // AssetName is the last part of the AssetPath.
        // Eg. if AssetPath is ScriptAssets/SomeAsset, then AssetName is SomeAsset.
        ksLog.Info(AssetName + ": " + str);
    }
}

Create Two Assets From Your Script Asset

Script assets must be in 'Resources' or asset bundles to be loaded on the client using Assets.Get or Assets.CreateInstance. References assigned to script assets in the editor using ksScriptAssetReference<T> do not need to be in 'Resources' or asset bundles. Before script assets can be loaded from asset bundles, you must call ksReactor.RegisterAssetBundle with the asset bundle.

Create a Server Room Script to Load Script Assets

Our server room script will demonstrate two different ways to load script assets. It will load one asset programmatically by name. It will load the other by assigning a ksEditable reference to it in the inspector. It will log the keys and values of both assets, and their asset ids and paths.

Instead of calling Assets.Get you could call Assets.CreateInstance. All calls to Get return the same object called a prefab, whereas calls to CreateInstance create a new copy of the asset prefab. If you modify the prefab returned by Assets.Get, subsequent calls to Assets.CreateInstance will create a copy with the modified values. Exising instances will not have their values changed. ksEditable asset references also reference the prefab returned by Assets.Get. You can check if a script asset instance is the original prefab or a copy by checking ksScriptAsset.IsPrefab. You can pass a prefab to Assets.Unload to unload a prefab, which turns the prefab into an asset instance (ksSciptAsset.IsPrefab becomes false) and future calls to Assets.Get or Assets.CreateInstance will reload a new prefab asset with the original asset values.

If you are not in a Reactor server, client, or asset script, to access the asset loader use ksScriptAsset.Assets instead of just Assets.

ServerRoom.cs

using KS.Reactor.Server;
using KS.Reactor;

public class ServerRoom : ksServerRoomScript
{
    [ksEditable]
    public CommonAsset AssetReference;

    // Called when the script is attached.
    public override void Initialize()
    {
        if (AssetReference != null)
        {
            AssetReference.LogStats();
        }
        // Load an asset by name or path. We are loading by name.
        CommonAsset asset = Assets.Get<CommonAsset>("CommonData2");
        if (asset != null)
        {
            asset.LogStats();
        }
    }
}

Create a Client Room Script to Load Script Assets

Like the server room script, our client room script will also demonstrate how to load script assets by name any by assigning a reference in the inspector. To get a serialized reference to a script asset in Unity, you must create a ksScriptAssetReference<T> field.

ClientRoom.cs

using KS.Reactor.Client.Unity;

public class ClientRoom : ksRoomScript
{
    public ksScriptAssetReference<CommonAsset> AssetReference;

    // Called after properties are initialized.
    public override void Initialize()
    {
        CommonAsset asset = AssetReference;// Implicit cast to the asset type.
        if (asset != null)
        {
            asset.LogStats();
        }
        // Load an asset by name or path. We are loading by name.
        asset = Assets.Get<CommonAsset>("CommonData2");
        if (asset != null)
        {
            asset.LogStats();
        }
    }
}

Assign References to CommonData1

Testing

In both the server and Unity logs you should see CommonData1's id and asset path followed by the keys and values you entered for it, then CommonData2's id and asset path followed by its keys and values.