[RuntimeInitializeOnLoadMethod] does not work on serialized generic classes.

This works:

[System.Serializable]
    public class ObjectReference : ScriptableReference<ScriptableObject>
    {
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
        static void Test()
        {
            Debug.Log("wooooo");
        }
    }

But this doesn't. Not sure how hard this would be to get working? It would be easier if we could have a base initializer so we don't have to create inititalizers for every subclass...or create concrete subclasses.

[System.Serializable]
    public class ScriptableReference<T> where T : ScriptableObject
    {
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
        static void Test()
        {
            Debug.Log("wooooo");
        }
    }

EDIT: Just realized I have been using this attribute wrong anyways.....it calls even if there is not an instance of the class...and only calls once. not on multiple instances. Darn.

This look strange if you think about it.
What kind of T type do you want Unity to call this function?
Unlike C++ templates which instantiated at compile time, C# generics only instantiated at runtime so there's not a good place where the system can decide if a type ScriptableReference exists or not.

1 Like

Yeah realized I have been using this wrong. Have to stick to intializing my classes :/ until I can come up with some referencing list system.

I recently stumbled upon this as well. It is a bummer this is not mentioned in the docs.

I solved this issue by using only a single [RuntimeInitializeOnLoadMethod] in a non-generic ScriptableObject (think of it like a registry) and put its instance under a Resources folder.

Then for everything else that needs to receive runtime initialization (for example: singleton ScriptableObjects for project-wide config) I wired them up to the registry instance.

In the [RuntimeInitializeOnLoadMethod], I find the instance of the registry with Resources.FindObjectsOfTypeAll<T>(). Then I manually invoke a custom RuntimeInit method on everything that was assigned to the registry instance in the inspector.

Seems to work well enough and it is pretty flexible.

If you have Odin, you can even define an interface like this and take in an array in your registry instead of defining a field for every type you have:

public interface IModule
{
    void RuntimeInit();
}

// then, in the registry:
[OdinSerialize] private IModule[] modules;
1 Like