ScriptableObject.CreateInstance(Type T) keep crashing

Hey, I stuck with this for a good moment now, somewhere in my code, I have this :

if (!_instance.ContainsKey(T) || _instance[T] == null)
        {
#if UNITY_EDITOR
            _instance[T] = (DataHolder)ScriptableObject.CreateInstance(T);
            Debug.Log(T.Name);
            return null;
            /*if (!Directory.Exists(Application.dataPath + "/DataHolders"))
                Directory.CreateDirectory(Application.dataPath + "/DataHolders");*/
            AssetDatabase.CreateAsset(_instance[T], "Assets/DataHolders/" + _instance[T].pathToBase + ".asset");
            AssetDatabase.SaveAssets();
#else
            t = LoadLast(T);
#endif
        }

But it crash everytime on the ScriptableObject.CreateInstance(T).
T is a class extending DataHolder.
_instance is a Dictionary
pathToBase is a simple string.

I’ve already use this code with another class, and it worked, so i don’t understand. I used the debug class around those lines to see where it stuck, all work until this, and i don’t get why.

Any help would be very pleasant.

thanks, FireCube

EDIT : there’s the DataHolder class :

//Code written by Etienne Desrousseaux, alias FireCube, for the updater package.
//
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using Crypting;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class DataHolder : ScriptableObject
{
    public static List<DataHolder> dataBases = new List<DataHolder>();

    public const string pathToBases = "Data";

    public string pathToBase
    {
        get
        {
            return GetType().ToString();
        }
    }

    public static Dictionary<Type, DataHolder> _instance = new Dictionary<Type, DataHolder>();

    public static T getInstance<T>() where T : DataHolder
    {
        T t = null;
        if (_instance.ContainsKey(typeof(T)))
            t = (T)_instance[typeof(T)];
        if (t == null)
        {
#if UNITY_EDITOR
            t = CreateInstance<T>();

            AssetDatabase.CreateAsset(t, "Assets/DataHolders/" + t.pathToBase + ".asset");
            AssetDatabase.SaveAssets();
#else
            t = LoadLast(typeof(T));
#endif
        }
        _instance[typeof(T)] = t;
        return t;
    }

    public static DataHolder GetInstance(Type T)
    {
        if (!_instance.ContainsKey(T) || _instance[T] == null)
        {
#if UNITY_EDITOR
            _instance[T] = (DataHolder)ScriptableObject.CreateInstance(T);
            Debug.Log(T.Name);
            return null;
            /*if (!Directory.Exists(Application.dataPath + "/DataHolders"))
                Directory.CreateDirectory(Application.dataPath + "/DataHolders");*/
            AssetDatabase.CreateAsset(_instance[T], "Assets/DataHolders/" + _instance[T].pathToBase + ".asset");
            AssetDatabase.SaveAssets();
#else
            t = LoadLast(T);
#endif
        }
        return _instance[T];
    }

#if UNITY_EDITOR
    public void open()
    {
        Selection.activeObject = this;
    }
#endif
    /// <summary>
    /// Load the last data holder of this type that have already been downloaded
    /// </summary>
    /// <param name="T">the type, must extend DataHolder class</param>
    /// <returns>the data holder loaded from last </returns>
    public static DataHolder LoadLast(Type T)
    {
        DataHolder dh = null;

        string path = Application.dataPath + "/" + pathToBases + "/" + ((DataHolder)CreateInstance(T)).pathToBase;

        if (File.Exists(path))
        {
            AssetBundle ab = AssetBundle.LoadFromMemory(
                File.ReadAllBytes(path)
                    .Decrypt(
                    SimpleConfig.getLine("pass", "UpdaterData")));
            dh = (DataHolder)ab.LoadAsset(T.Name, T);
        }

        return dh;
    }

    /// <summary>
    /// Download and save to disk a data holder, debug parameter exist for UNITY_EDITOR only
    /// </summary>
    /// <param name="T">the type for which we want to download the base</param>
    /// <param name="onDone">the function to be executed when the download is finished</param>
    /// <param name="onError">the function to be executed if an error happen durring the download, the saving to disk or when loading the base</param>
    /// <param name="onUpdate">the function to be executed every <paramref name="updateRate"/>, sending the progress</param>
    /// <param name="updateRate">the rate at which <paramref name="onUpdate"/> is called</param>
    public static IEnumerable DownloadDataHolder(Type T, Action<DataHolder> onDone = null, Action<string> onError = null, Action<float> onUpdate = null, float updateRate = 0.05f
#if UNITY_EDITOR
        , bool debug = false//reduce size on build
#endif
        )
    {
        bool update = onUpdate != null;

        string url = SimpleConfig.getLine("website", "UpdaterData") + "/" + T.Name + ".dat";
        WWW www = new WWW(url);
#if UNITY_EDITOR
        if (debug)
            Debug.Log("Start downloading " + url + "

Corresponding Data Holder is " + T.FullName);
#endif
if (update)
{
while (!www.isDone)
{
yield return new WaitForSeconds(updateRate);
Action temp = onUpdate;
if (temp != null)
{
temp(www.progress / 3);
}
}
}
else
yield return www;

        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogError("Error while downloading data holder : " + www.error + "

calling error function");
Action temp = onError;
if (temp != null)
temp("Error while downloading data holder : " + www.error);
}
else
{
#if UNITY_EDITOR
if (debug)
Debug.Log(“Done downloading " + url + "
" + www.bytesDownloaded + " bytes downloaded”);
#endif
byte data = www.bytes;

            www.Dispose();

            byte[] decrypted = data.Decrypt(
                SimpleConfig.getLine("pass", "UpdaterData"));

            string path = Application.dataPath + "/" + pathToBases + "/" + ((DataHolder)CreateInstance(T)).pathToBase;
            bool error = false;
            try
            {
                File.WriteAllBytes(path, data);
            }
            catch
            {
                Debug.LogError("Error while writting base to file, calling error function");
                error = true;
                Action<string> temp = onError;
                if (temp != null)
                    temp("Error while writting base to file");
            }
            if (!error)
            {
#if UNITY_EDITOR
                if (debug)
                    Debug.Log("Done saving " + T.FullName + " to " + path);
#endif

                var bundle = AssetBundle.LoadFromMemoryAsync(decrypted);

                if (update)
                {
                    while (!bundle.isDone)
                    {
                        yield return new WaitForSeconds(updateRate);
                        Action<float> temp = onUpdate;
                        if (temp != null)
                        {
                            temp((bundle.progress + 1) / 3);
                        }
                    }
                }
                else
                    yield return bundle;

                var dh = bundle.assetBundle.LoadAssetAsync(T.Name, T);

                if (update)
                {
                    while (!dh.isDone)
                    {
                        yield return new WaitForSeconds(updateRate);
                        Action<float> temp = onUpdate;
                        if (temp != null)
                        {
                            temp((dh.progress + 2) / 3);
                        }
                    }
                }
                else
                    yield return dh;

                Action<DataHolder> temp2 = onDone;
                if (temp2 != null)
                {
                    temp2((DataHolder)dh.asset);
                }
#if UNITY_EDITOR
                if (debug)
                    Debug.Log("Done with data holder " + T.FullName);
#endif
            }
        }

    }
}

and the class that call everything is there :

//Code written by Etienne Desrousseaux, alias FireCube, for the updater package.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public class DataHolderWindow : EditorWindow
{
    List<Type> types;
    
    void OnGUI()
    {
        if (types == null)
            types = new List<Type>(FindDerivedTypes(typeof(DataHolder).Assembly, typeof(DataHolder)));
        foreach (var T in types)
        {
            if (GUILayout.Button(Regex.Replace(T.ToString(), "([A-Z])", " $0")))
            {
                open(T);
            }
        }
    }
    void open(Type T)
    {
        MethodInfo m = T.BaseType.GetMethod("GetInstance");
        object j = m.Invoke(null, new object[] { T });
        //T.GetMethod("open").Invoke(j, null);
    }

    public IEnumerable<Type> FindDerivedTypes(Assembly assembly, Type baseType)
    {
        return assembly.GetTypes().Where(t => t != baseType &&
                                              baseType.IsAssignableFrom(t));
    }

    [MenuItem("Updater/Data Holder List")]
    static void Init()
    {
        DataHolderWindow window = GetWindow<DataHolderWindow>();
        window.titleContent.text = "Data Bases List";
        window.Show();
    }
}

The Debug are still in there

Thx

NEW EDIT :

I found the problem, but first, here’s my Demo class, that is the one that should open and create :

//Auto generated resource data holder the 7/3/2016
//Using the Updater package
using UnityEngine;

public class Demo : DataHolder
{

    #region fields
    public static new string name
    {
        get { return instance._name; }
        set { instance._name = value; }
    }
    public string _name;

    public static GameObject prefab
    {
        get { return instance._prefab; }
        set { instance._prefab = value; }
    }
    public GameObject _prefab;

    public static float speed
    {
        get { return instance._speed; }
        set { instance._speed = value; }
    }
    public float _speed;


    #endregion

    public static Demo instance
    {
        get { return getInstance<Demo>(); }
    }

    [InspectorCallable]
    public void Reset()
    {
        name = "";
        prefab = null;
        speed = 5f;
    }
}

The problem is, indeed, the function Reset. Unity freeze when it’s not commented, but all is good if it is commented, and i can’t explain myself why…

There are a few things that are required for CreateInstance to work are:

  • Your base class (DataHolder) has to be derived from ScriptableObject
  • Your actual concrete class has to be placed in a file that matches the classname.

both of those points are missing in your question, so we can’t really tell what you did wrong.

If everything is right then there must be something wrong inside your concrete class. However your class is missing as well so again we can’t help you.

Ok, look’s like I was just unlucky, this only happen with Reset, or probably some special functions…