Serialization lost when loading asset bundles in runtime

Hello,

We have been working with asset bundles to load code and scenes at runtime, but we couldn’t find a way to get serializable classes/structs to work as well. So we have two different Unity projects: 1 in which we create a scene and 1 in which we want to load that scene at runtime.

Project 1: Creating the Scene
The scene that is going to be in the assetbundle contains an object called ‘MyObject’ which has a component with 3 fields: a string, a Vector3 and a custom serializable struct. Unity screenshot original

The code of this component is this:
Component code

public class SerializeThis : MonoBehaviour {
    public string MainName;
    public Vector3 vector;
    public SerializedField field;

    private void Start()
    {
        Debug.Log(string.Format("{0};{1};{2}", field.Name, field.Number, field.Check));
    }
}

[Serializable]
public struct SerializedField
{
    public string Name;
    public int Number;
    public bool Check;
}

This script is added to its own assembly via assembly definitions and I then build 2 assetbundles (1 for the code and 1 for the scene):
Building bundle code

public static class BuildBundles {

        private static List<AssetBundleBuild> Bundles;

        [MenuItem("BuildBundles/Build")]
        public static void Build()
        {
            Bundles = new List<AssetBundleBuild>();
            Bundles.Add(new AssetBundleBuild()
            {
                assetBundleName = "SceneBundle",
                assetNames = new string[] { "Assets/Scenes/SampleScene.unity" }
            });
            Bundles.Add(new AssetBundleBuild
            {
                assetBundleName = "ScriptBundle",
                assetNames = new string[] { "Assets/ScriptsAssembly.bytes" }
            });
            BuildPipeline.BuildAssetBundles(@"[build location]", Bundles.ToArray(), BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        }
    
}

Project 2: Loading the scene
I then open the loading project where I load the assetbundles like so:
Loading bundle code

public class Loader : MonoBehaviour {
 
    void Start ()
    {
        LoadCode();
        LoadScene();
    }

    private void LoadCode()
    {
        var filename = @"[build location]\scriptbundle";
        var codeBundle = AssetBundle.LoadFromFile(filename);
        var assetName = codeBundle.GetAllAssetNames()[0];
        var txt = codeBundle.LoadAsset<TextAsset>(assetName);
        Assembly.Load(txt.bytes);
    
    }

    private void LoadScene()
    {
        var filename = @"[build location]\scenebundle";
        var sceneBundle = AssetBundle.LoadFromFile(filename);
        var scenePath = sceneBundle.GetAllScenePaths().First();
        SceneManager.LoadScene(Path.GetFileNameWithoutExtension(scenePath));
    }
}

Result vs expectation
If I then run the loading project from the editor, I expect the scene to load, the ‘MyObject’ to be present and all variables set as they were in the above attachment. However, the serialized struct is not shown and empty according to the console.
Unity object loaded

When we try to load the assetbundles in the same project as they were created, the result was as expected, so we think something is going wrong with the loading of assemblies vs the serialization in Unity. The code is loading as we can see the ‘SerializeThis’ class as component in the loading project.

Any thoughts/advice on how to get the expected result?

1 Like

I suppose the post was a bit too long to read easily, so I edited all code/images into spoilers. Hopefully someone can help me point to why the serialization is not present in the loading project.

I’m also having the same issue…

did you find any solution…

Having the same issue here in Unity 2018.4.4. Loading a scene or prefab with custom serializable class attributes does not work when the corresponding class is also loaded via reflection at runtime.

For example, a custom UnityEngine.UI Button implementation click handler event is unable to maintain the serialized click handler callback as it comes through as null after loading the asset bundle.

Anyone have any idea?

The issue described here and here:

Seem to be describing the same situation.

Still no solution, but linking them together in case it provides any value.

There is a case for this issue that you can track here: Unity Issue Tracker - Assetbundle is not loaded correctly when they reference a script in custom DLL which contains [System.Serializable] in the build

It’s been assigned to the team that handles scripting type loading & de-serialization

2 Likes

Chiming back in that I resolved this issue (for now) by implementing customer serializers:
https://docs.unity3d.com/Manual/script-Serialization-Custom.html
for the custom serializable class that was being dropped. It’s an ugly hack but it keeps us going for now.

I voted on and will keep an eye on that issuetracker item for a proper fix.

1 Like

So it is a static/fixed implementation based on the specific type?

Probably this is solution which slumtrimpet write about (at least it works) :

[System.Serializable]
public class SerClassSample
{
    public string Text;
    public int Number;
}

public class ExampleMonoBehaviour : MonoBehaviour, ISerializationCallbackReceiver
{
    [SerializeField]
    private SerClassSample _test;

    [HideInInspector, SerializeField]
    private string _testText;
    [HideInInspector, SerializeField]
    private int _testNumber;

    public void OnAfterDeserialize()
    {
        _test = new SerClassSample()
        {
            Number = _testNumber,
            Text = _testText
        };
    }

    public void OnBeforeSerialize()
    {
        _testNumber = _test.Number;
        _testText = _test.Text;
    }
}

Also you can just serialize SerClassSample to json and save it to string field

I see it’s not fixed here either. Just posting so I can follow up on the thread if I find a solution. The solution posted above won’t work if you need to serialize a List - which is the issue I’m dealing with. I’m gonna submit to ugly hacks and instead of a list, I’m going to add a MonoBehavior to my gameObject for each item thatwould be in the list, then instead of foreaching the list, I’ll foreach a GetComponents().

Ugh. Doing it that way makes me feel sick.

i dont understand why you do this, monobehaviour contain all member that you need while you write them agin.

@Ryanc_unity ping!

We are suffering this…It’s been years now (2019), any news? Is it simply lack of priority, complexity to solve it, …?

4 Likes