- Home /
CustomEditor for an ScriptableObject asset only works after recompile.
Hi, I'm really new to ScriptableObjects and Editor scripting and I'm having some trouble creating some "Setting" assets for some functionality in my project... Basically, it's got to do with some Lists of AudioClips. I want the designer to be able to drop the clips in and be able to reuse the asset anytime. But when you first create the asset and use the custom editor to try and change the amount of clips in the array, the compiler throws a null ref exception... But if Unity recompiles for any reason, then the Asset starts to work right! Only new Assets fail... until Unity recompiles for whatever reason...
Here is the SO:
[System.Serializable]
[CreateAssetMenu(menuName = "Sfx/ManagerData")]
public class Sfx_SettingsAsset : ScriptableObject
{
//tag data
public List<string> ManagerTags = new List<string>() { "Wood", "Concrete", "Grass", "Metal", "Water", "Mud", "Snow", "Fire" };
//Allows for more than one sound to avoid machinegun effect
[HideInInspector] public List<List<AudioClip>> MasterClips;
public List<AudioClip> SfxDefault;
public List<AudioClip> Sfx01;
public List<AudioClip> Sfx02;
public List<AudioClip> Sfx03;
public List<AudioClip> Sfx04;
public List<AudioClip> Sfx05;
public List<AudioClip> Sfx06;
public List<AudioClip> Sfx07;
public List<AudioClip> Sfx08;
public bool[] UseDefaultTag = { true, true, true, true, true, true, true, true };
public int[] SfxAmount = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/// <summary>
/// The min volume of the sfx produced on contact.
/// </summary>
public float SfxMinVol = .5f;
/// <summary>
/// The max volume of the sfx produced on contact.
/// </summary>
public float SfxMaxVol = 1f;
/// <summary>
/// The min pitch of the sfx produced on contact.
/// </summary>
public float SfxMinPitch = .4f;
/// <summary>
/// The max pitch of the sfx produced on contact.
/// </summary>
public float SfxMaxPitch = 1f;
}
Here is the part of the editor script which returns the error:
//inside public override void OnInspectorGUI()
//get access to the info in you script
LimbSfxManager s = (LimbSfxManager)target;
//......//
s.MasterClips = new List<List<AudioClip>>() { s.SfxDefault, s.Sfx01, s.Sfx02,
s.Sfx03, s.Sfx04, s.Sfx05, s.Sfx06, s.Sfx07, s.Sfx08 };
foreach (var clips in s.MasterClips)
{
//Debug.Log(s.SfxAmount[i]);
s.SfxAmount[i] = EditorGUILayout.DelayedIntField("Audio clips in " + (i == 0 ? "Default" : s.ManagerTags[i-1]) + " Keyword:", s.SfxAmount[i]);
int i2 = 0;
while (i2 < s.SfxAmount[i])
{
if (clips.Count != s.SfxAmount[i]) //Null ref right HERE!
{
//make temp list
var tempList = s.MasterClips[i];
//get old size
int tempsize = s.MasterClips[i].Count;
//if the old size is less
if (tempsize < s.SfxAmount[i])
{
while (tempsize < s.SfxAmount[i])
{
//add a new clip until it matches the new size
AudioClip tempClip = new AudioClip();
tempList.Add(tempClip);
tempsize++;
}
}
//if the old size is more
if (tempsize > s.SfxAmount[i])
{
while (tempsize > s.SfxAmount[i])
{
//remove last clip until it matches the new size
tempList.RemoveAt(s.SfxAmount[i]);
tempsize--;
}
}
//assign the modified list as the EditorClips
s.MasterClips[i] = tempList;
}
if (s.SfxAmount != null)
{
s.MasterClips[i][i2] = (AudioClip)EditorGUILayout.ObjectField((i == 0 ? "Default" : s.ManagerTags[i-1]) + " Sound clip " + (i2 + 1) + ":", s.MasterClips[i][i2], typeof(AudioClip), false);
}
else
{
EditorGUILayout.HelpBox("There are no clip lists defined.", MessageType.Warning);
}
i2++;
}
EditorGUILayout.Space();
EditorGUILayout.Space();
i++;
}
The rest of the code (with the tags) doesn't give any problems (so I left it out to save space). And I'm using a practically identical piece of code for the "Manager" gameobject sitting in the hierarchy, and that one doesn't seem to give me any errors... I just slot in the (fixed-after-recompile-for-whatever-reason) assets and it reads them and modifies them without errors.
I just don't get it, why do the asset files work fine after a recompile but not upon creation? I tried setting the target as dirty in OnEnable in the editor script and also tried marking stuff as [System.Serializeable]. But no difference... I only started programming a few months ago, so as you probably already noticed I still don't get serialization and other stuff very much yet...
Anyway, any advice will be greatly appreciated.
Answer by PineTreeDev · May 19 at 09:50 AM
Hello!
Old question, but I figured it could be answered
In your Scriptable Object manager, you have these lists of clips that are basically not initialized. When you are going through your clips in the editor class, and ask for the count of those lists, they are empty the first time after creating an asset!
So when you do your assembly reload, unity forces initialization on assets belonging to that assembly reload, hence the lists no longer throw a null reference, because the editor initialized them for you!
Fixing it is just a matter of, either in your editor script or in the Scriptable Object Reset function, going through all of those clips lists and initializing them.
public List<AudioClip> SfxDefault;
public List<AudioClip> Sfx01;
public List<AudioClip> Sfx02;
public List<AudioClip> Sfx03;
public List<AudioClip> Sfx04;
public List<AudioClip> Sfx05;
public List<AudioClip> Sfx06;
public List<AudioClip> Sfx07;
public List<AudioClip> Sfx08;
Your answer
Follow this Question
Related Questions
Serializing a ScriptableObject without creating an asset for it? 2 Answers
Add lines to a script from another script 0 Answers
pass child class to ScriptableObject.CreateInstance<> ? 1 Answer
ScriptableObject with Custom Editor resetting data in inspector 1 Answer
Custom assets give Missing (Mono Script) 0 Answers