- Home /
AssetDatabase.LoadAssetAtPath() not working after any sort of project change.
I have created a class which holds data about an object, which looks like the following:
using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
[Serializable]
public class SerializedParameters : ScriptableObject
{
private SerializedParameter[] _items;
public SerializedParameter[] Items
{
get
{
return _items;
}
set
{
_items = value;
}
}
public SerializedParameters()
{
Items = new SerializedParameter[0];
}
public bool Contains(string name)
{
for(int i = 0; i < Items.Length; i++)
{
if(Items[i].Name == name)
{
return true;
}
}
return false;
}
public object GetValue(string name)
{
if(Contains(name))
{
for(int i = 0; i < Items.Length; i++)
{
if(Items[i].Name == name)
return Items[i].Value;
}
return null;
}
else
{
return null;
}
}
public void AddParam(string name, object val)
{
SerializedParameter[] temp = new SerializedParameter[Items.Length + 1];
for(int i = 0; i < Items.Length; i++)
{
temp[i] = Items[i];
}
temp[Items.Length] = new SerializedParameter(name, val);
Items = temp;
}
}
[Serializable]
public class SerializedParameter
{
private string _name;
private object _value;
public string Name
{
get
{
return _name;
}
set
{
Debug.Log ("Name Field changed: " + value);
_name = value;
}
}
public object Value
{
get
{
return _value;
}
set
{
Debug.Log ("Value Field changed: " + value);
_value = value;
}
}
public SerializedParameter(string name, object val)
{
Name = name;
Value = val;
Debug.Log ("Constructor Called: Name-" + name + " Value-" + val );
}
public SerializedParameter()
{
Debug.Log ("Constructor Called");
}
}
The purpose of this is so that at run time, if the component does not exist on the object, I can perform a replace of the component and the metadata about the component (public fields, etc.) will be restored as well, so that I can load a scene at runtime and bring in the scripts as a dll resource. The serialize and deserialize functions look like this:
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Reflection;
using System;
[ExecuteInEditMode()]
public class ComponentBase : MonoBehaviour {
public virtual void Serialize()
{
SerializedParameters parameters = ScriptableObject.CreateInstance<SerializedParameters>();
Type type = this.GetType();
foreach(FieldInfo info in type.GetFields())
{
foreach(Attribute att in info.GetCustomAttributes(true))
{
if(att.ToString().Contains("SerializableProperty"))
{
object obj = info.GetValue(this);
//Debug.Log (info.Name + " " + obj );
parameters.AddParam(info.Name, obj);
}
}
}
ComponentManager cm = gameObject.GetComponent<ComponentManager>();
if(cm != null)
{
AssetDatabase.CreateAsset(parameters, "Assets/" + cm.GUID + ".asset");
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
public virtual void Deserialize()
{
ComponentManager cm = gameObject.GetComponent<ComponentManager>();
SerializedParameters parameters = AssetDatabase.LoadAssetAtPath ("Assets/" + cm.GUID + ".asset", typeof (SerializedParameters)) as SerializedParameters;
if(parameters != null)
{
Type type = this.GetType();
foreach(FieldInfo info in type.GetFields())
{
foreach(Attribute att in info.GetCustomAttributes(true))
{
if(att.ToString().Contains("SerializableProperty"))
{
if(parameters.Contains(info.Name))
{
info.SetValue(this, parameters.GetValue(info.Name));
}
}
}
}
}
}
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
void Awake()
{
Deserialize();
}
}
As you can see, I use reflection to go through all of the fields, and for every field store a SerializedParameter into the array in my SerializedParameters object. The whole SerializedParameters object is then saved as an asset using a unique GUID. If the component is ever missing, I simply run the deserialize function and the component comes back repopulated correctly, so that the scripts can activly choose whether or not to use a class at runtime (like an external dll) or to use the scripts in the project folder.
If I run serialize on all objects, and asset with their GUID pops up in the Project panel. Then I can delete the component, deserialize and all works like a charm. However, If any changes to the project are made, such as changing the directory of any script, changing any script contents, or restarting unity, the LoadAsset at path does not work correctly. The object comes back, the correct number of fields are there, and all of the name values of the SerializedParameter object are correctly assigned but the Value property of the SerializedParameter objects are all null.
Thank you for your time to look at this problem.