ScriptableObject field is never null?

Hi,

I have a simple ScriptableObject class that holds a serialized field _activeGraph. However, I noticed that its value is never null, but never assigned to either! Here’s part of the class:

[System.Serializable]
public class NodeGraphs : ScriptableObject {
[SerializeField]
NodeGraph _activeGraph;

public NodeGraph activeGraph {
    get{
        return_activeGraph;
    }
    set{
        _activeGraph = value;
        Debug.LogWarning("set active to "+value);
    }
}

Now in my Editor class I instantiate a .asset instance of it if it doesn’t exist. After that, I immediately print instance.activeGraph and sure enough, I get an instance! Does SerializeField enforce existance? Or am I missing something else?

Thanks,
Patrick

Is NodeGraph a struct or a class? Serializing enforces a memory location I believe, but not really “existence” in the case of reference types. If you’re serializing a struct, on the other hand, it may exist as if created with a parameterless constructor (possibly?).

Sorry, I forgot to mention; NodeGraph is just a (serializable) class.

I am having a similar issue.

I am creating a Weapon/Skill system that will gather all the data it needs from a ScriptableObject. In order to reduce clutter, instead of all the data being in one class, it will be put into what ever class requires the data.
So for example, if I have multiple ammo types such as Clips or Charge, in the scriptableobject I will have an enum to choose which ammo type I want to use, which would then display the appropriate serializable ammo class for me to put data into.

Example code
Click for code

using UnityEngine;

namespace SkillSystem
{
    [System.Serializable]
    public class Skill : ScriptableObject
    {
        //Other fields...

        public enum AmmoType {None, Clips, Charge}
        public AmmoType ammoType;
        public AmmoClips ammoClips;
        public AmmoCharge ammoCharge;
    }
}
using UnityEngine;

namespace SkillSystem
{
    [System.Serializable]
    public class AmmoClips : Ammo
    {
        [SerializeField] int maxAmmoInClip;
        [SerializeField] int maxClips;
     
        //Ammo Code stuff...
    }
}
using UnityEngine;

namespace SkillSystem
{
    [System.Serializable]
    public class AmmoCharge : Ammo
    {
        [SerializeField] int maxCharge;
        [SerializeField] float chargeSpeed;

        //Ammo Code stuff...
    }
}

And so the editor code is something like this…
Click for Editor Code

using UnityEngine;
using UnityEditor;
using SkillSystem;

[CustomEditor(typeof(Skill))]
public class SkillEditor : Editor
{
    public override void OnInspectorGUI()
    {
        Skill skill = (Skill)target;

        skill.ammoType = (Skill.AmmoType) EditorGUILayout.EnumPopup("Ammo Type", skill.ammoType);
    
        if(skill.ammoType == Skill.AmmoType.Clips)
        {
            SetProperty("ammoClips");
            skill.ammoCharge = null;
        }
        else if(skill.ammoType == Skill.AmmoType.Charge)
        {
            SetProperty("ammoCharge");
            skill.ammoClips = null;
        }
    }

    void SetProperty(string fieldName)
    {
        SerializedProperty property = serializedObject.FindProperty(fieldName);
        serializedObject.Update();
        EditorGUILayout.PropertyField(property, true);
        serializedObject.ApplyModifiedProperties();
    }
}

So I choose which ammo type I want, it displays the correct class and all is well, except for the “… = null” part.
If I set one ammo type, choose another, and then switch back to the old one, the values were erased as expected. However, if I press play and try to access both ammo classes, none of them would return null. The ammo class I didnt have selected would just return values of 0.

The idea behind setting the classes I am not using to null would be to keep memory usage low.
In this particular case it might not be so much of an issue, but maybe down the road it would be.

Does anyone know of a way to choose which ScriptableObjects gets saved and which stay null?

http://forum.unity3d.com/threads/serialization-best-practices-megapost.155352/ Start with this.

My assumption is that your base Ammo class, which you don’t show, isn’t inheriting from scriptable object. UnityEngine.Object is special in that only things derived from it (including ScriptableObject and MonoBehaviour) are tracked by the editor referentially. It’s the only way for the editor to track references of an object, including null and multiple references to a single instance of an object.

Otherwise, Unity serialization (which you usually find out about when it deserializes everything when you exit play mode) basically treats serialized classes as structs, which is ironic since structs were only supported recently. Any referencing is broken, with each reference becoming a new instance with the same data, and nothing is left null, usually getting default values.

The link was a nice read =)

So the issue is that since unity is doing this pull data, clear it, put back thing, it has no way of knowing if the class was null, so it just assigned it something. However, if I was using a ScriptableObject or some other Unity Object, it would then be able to realize that something was not assigned and is null.

I would need to have my Ammo class be a ScriptableObject, create the classes through CreateInstance(), and manually make the GUI for assigning those values as well (where in my case above I can just use SerializedProperty to do the gui work) in order to be able to have my other ammo class to be properly seen as null.
(Or create the ammo scriptableobject as a .asset file, but I dont want that mess)

Makes sense, and in this case I will just continue with having the values just be set to 0.

Thanks for the help ^^