Johannes
Johannes

Reputation: 6419

Why are nested resources references in a ScriptableObject asset not loaded?

Please read the entire question, and run the example before posting an answer.


Overview

I ran into some inconsistent behavior in Unity 5.6.1 when loading nested assets in a static Editor script (so in the static constructor of a class marked with [InitializeOnLoad]).

I am loading a ScriptableObject Asset with Resources.Load, and the ScriptableObject has a public reference to another asset resource, let's suppose a GameObject Prefab. From this point I will refer to the ScriptableObject as the 'Wrapper', since in this simplified example that is the only purpose it serves.

While Resources.Load correctly returns the Wrapper, the nested Prefab reference is often not yet loaded during the first run, but is loaded after the second run:

Screencap showing that the prefab is not loaded on the first run, but is on the second

To my understanding this is an order of execution issue where the Prefab resource in question has not been loaded yet during static construction, and on subsequent runs it remains cached.

I assumed that when loading in an asset with a serialized reference to another asset, that the nested asset would automatically be loaded by default, regardless of whether this is during static init or not. This however does not seem to be the case here.

Proof that the Wrapper asset does indeed correctly reference the Prefab in its serialized data (with Asset Serialization set to Force Text): Proof that prefab reference is correctly serialized

I have also tried to use AssetDAtabase.LoadAssetAtPath (at least while in the editor), which has not made a difference.


Example Project

You can download a UnityPackage here, which contains the following:

enter image description here

Or reproduce it as follows:


Rationale

The example here is deliberately simplified, but it is based on real projects that use ScriptableObjects for storing/sharing configuration data for custom systems.

Please do not reply with the following:

What I am looking for:


EDIT: It should also be noted that weirdly enough, when I close the project and open it again I see the following:

enter image description here

This, I really don't understand.

Upvotes: 5

Views: 3233

Answers (1)

Galandil
Galandil

Reputation: 4249

There's a misconception regarding your question.

The reference is passed to the Loader class, and you can check it by logging Wrapper.Value after scene initialization is completed.

Most probably, the problem is (as you pointed out) in the execution/serialization order, apparently it happens something like this:

  • The Loader constructor is called, and Wrapper reference is passed correctly.
  • Debug.Log(Wrapper.Value) returns null because the fields of the scriptable object haven't yet been serialized
  • Wrapper's fields are serialized, now logging Wrapper.Value shows correctly ExampleObject.

So, unless you're planning something "special" to do with the Wrapper fields during initalization, there's really not a problem in your code: I tried to run Debug.Log(Loader.Wrapper.Value) during the OnEnable of ExampleWrapper, and I got the correct value.

Regarding your edit, apparently it happens "by Design", as clearly stated in this issue: https://issuetracker.unity3d.com/issues/unityeditor-dot-initializeonload-calls-the-constructor-twice-when-the-editor-opens

Upvotes: 3

Related Questions