AssetDatabase.LoadAssetAtPath() doesn't always work

AssetDatabase.LoadAssetAtPath() seems to only work after AssetDatabase.CreateAsset() is first called. But doing so would destroy the Asset that is already there. If I call AssetDatabase.LoadAssetAtPath() immediately after loading the Unity editor, it does not return the full data. Can anyone see what I’m doing wrong in the code sample below?

using UnityEngine;

using UnityEditor;



[System.Serializable]

public class AssetTest : ScriptableObject

{

	public 		UIObjectSerializedData m_UIObjectSerializedData;

	public		string	m_OtherString;

	

	[System.Serializable]

	

	public class UIObjectSerializedData

	{

		public 	string 	m_NameString;

		public	int		m_IntTest;

	}



	public static void CreateAsset(AssetTest asset)

	{

		Debug.Log("CreateAsset: " + asset.name + "

");

		AssetDatabase.CreateAsset(asset, "Assets/AssetTest.asset");

	}

	

	public static AssetTest LoadAsset(string assetPath)

	{

		var  asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(AssetTest));

		Debug.Log("LoadAsset: " + assetPath + "=" + asset.name + "

");

		return asset as AssetTest;

	}

	

	public string ShowData()

	{

		string outString = m_OtherString + ", " + m_UIObjectSerializedData.m_NameString + ", " + m_UIObjectSerializedData.m_IntTest.ToString();

		return outString;

	}

}



public class AssetTestMenu

{

	static string AssetTestPathName = "Assets/AssetTest.asset";

	[MenuItem("AssetTest/Test Create")]

	static void TestCreateMenu()

	{

		AssetTest asset = ScriptableObject.CreateInstance<AssetTest>();

		asset.name = "MytestAsset";

		AssetTest.CreateAsset(asset);

		asset.m_OtherString = "OtherString";

		asset.m_UIObjectSerializedData.m_NameString = "This space intentionally left blank.";

		asset.m_UIObjectSerializedData.m_IntTest = 12345;

		

		AssetDatabase.SaveAssets();

		

		//	try loading it right away to see if we got the right data

		Debug.Log("Test Create: NameString=" + asset.ShowData() + "

");

		TestLoadMenu();

	}

	

	[MenuItem("AssetTest/Test Load")]

	static void TestLoadMenu()

	{

		var loadedObj = AssetTest.LoadAsset(AssetTestPathName);

		AssetTest asset = loadedObj as AssetTest;

		Debug.Log("Test Load: NameString=" + asset.ShowData() + "

");

	}

}

Output
If AssetTest/Test Create is selected:

CreateAsset: MytestAsset

Test Create: NameString=OtherString, This space intentionally left blank., 12345

LoadAsset: Assets/AssetTest.asset=AssetTest

Test Load: NameString=OtherString, This space intentionally left blank., 12345

If AssetTest/Test Load is selected without first choosing AssetTest/Test Load:

LoadAsset: Assets/AssetTest.asset=AssetTest

Test Load: NameString=, , 0

,I am also having this problem. Have you come up with a solution to it? In my case the object which has been created comes back out, and some of the fields are populated and others are null. In terms of your class structure, the m_NameString variable is populated but the m_IntTest is null.

4 Answers

4

Are you positive that an instance of type AssetTest exists at that path?

Has it been instantiated and does it contain valid data?

I notice that AssetTest is a ScriptableObject. Is AssetTest/AssetTest.asset the location of the script or the location of an instance of that type?

To create an instance of a ScriptableObject you can call ScriptableObject.CreateInstance. This creates an actual instance of whatever type you specify.

Sorry if you already knew this... Just trying to help.

I'm assuming you already understand this, since otherwise you'd be erasing your script when you create a new Asset.

I believe there is a bug in Unity where if you have a class like this:

public class UIObjectSerializedData
{

   public    string    m_NameString;

   public    int       m_IntTest;

}

that you serialize, then only the LAST variable of that class is actually serialized rather than the entire class! You can test this by switching the order of m_NameString and m_IntTest in the class.

I worked around this by not having a class serialized, but by simply taking the members out of that class and putting them in the class above it and serializing the field directly.

It would be nice if the class serialized properly. This would make my architecture somewhat cleaner. But for now, this seems to be an acceptable workaround.

Actually mine was a result of unity not being able to serialize a System.Object type.

I was too lazy to read question, but this might help

if (EditorApplication.isCompiling) {
            return;
} 
//only do loading from asset database / re-creating assets if not compiling.