Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by SHEePYTaGGeRNeP · Nov 27, 2017 at 03:51 PM · custom editorpropertydrawerserializedpropertycustom inspector

SerializedObject.FindProperty returning null

Firstly I am missing my inheritFrom field when using the normal Inspector (not anymore when I inherit from UnityEngine.Object, then there's just 1 field):

 [DataContract]
 [System.Serializable]
 public class BotPersonality : UnityEngine.Object
 {

 [DataMember]
 [JsonProperty]
 [SerializeField]
 private BotPersonality _inheritFrom;
 
 [DataMember]
 [JsonProperty]
 [SerializeField]
 private string[] _possibleNames = {"test1", "test2"};

Inspector normal

I want to write a custom inspector for inheriting / copying fields from another object with _inheritFrom.

However I am getting NullReferenceExceptions ( SerializedObject.FindProperty returns null) for all my fields. nullRefException

it says it can't find the skill property, but it is clearly defined and it works in the first image.:

 [DataMember]
 [SerializeField]
 public int skill = 1;

The skill variable is serializable.

Below is my PropertyDrawer class

     [CustomPropertyDrawer(typeof(BotPersonality))]
     public class BotPersonalityDrawer : PropertyDrawer
     {
         private readonly Type _type = typeof(BotPersonality);

 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
 {
     BotPersonality botPersonality =
         Utils.GetActualObjectForSerializedProperty<BotPersonality>(this.fieldInfo, property);    
     this.ShowPersonality(botPersonality, property);
 }

     private void ShowPersonality(BotPersonality bot, SerializedProperty property)
     {
         int prevIndentLevel = EditorGUI.indentLevel;
          foreach (FieldInfo fieldType in this._type.GetFields()
                         .Where(x => x.IsDefined(typeof(DataMemberAttribute), false)))
         {
         ...
         var serializedProperty = property.serializedObject.FindProperty(fieldType.Name);
             EditorGUILayout.PropertyField(serializedProperty);
         }
 }
 }

The code for GetActualObjectForSerializedProperty can be found here: http://sketchyventures.com/2015/08/07/unity-tip-getting-the-actual-object-from-a-custom-property-drawer/ (I changed it so it works with lists too ), but this an object that is not null.

Help would be much appreciated. I can't see what I'm doing wrong.

EDIT: To clarify, I'm not looking for help with the inheritance / copy an object.

EDIT2: I've created it as small as I can and it still gives the same NullRef Exception:

 [DataContract]
 [System.Serializable]
 public class BotPersonalitySmall : MonoBehaviour
 {
     [DataMember]
     [SerializeField]
     public int skill = 1;
     [DataMember]
     [SerializeField]
     private BotPersonalitySmall _inheritFrom;
     [DataMember]
     [Overridable]
     public BotPersonality.WaypointSteeringInfo waypointSteering;
 }

The class I'm trying to serialize

The PropertyDrawer:

 [CustomPropertyDrawer(typeof(BotPersonalitySmall))]
 public class BotPersonalitySmallDrawer : PropertyDrawer
 {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         // Using BeginProperty / EndProperty on the parent property means that
         // prefab override logic works on the entire property.
         EditorGUI.BeginProperty(position, label, property);
         var serializedProperty = property.serializedObject.FindProperty("skill");
         EditorGUILayout.PropertyField(serializedProperty);
         EditorGUI.EndProperty();
     }
 }

It still can't find the property skill. I've changed the inheritance on BotPersonality to UnityEngine.Object or keep it empty, but that didn't help.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Nov 27, 2017 at 06:57 PM

This is quite confusing. You showed random bits of your code and your inspector. What does "BotPersonality" look like? Is it a serializable class / struct? What Tyoe does "this._type" refer to?


This line looks suspicious:

 var serializedProperty = property.serializedObject.FindProperty(fieldType.Name);


You may have the wrong idea in mind what a SerializedObject is. SerializedObjects are only those objects which are derived from UnityEngine.Object. Custom serializable classes are not objects from the serialization systems point of view. Custom serializable classes get simply serialized "inline" as sub fields.


The SerializedProperty class has a method called FindPropertyRelative which can search for a sub property. It's possible to use FindProperty on the serializedObject when you use a correct property path. In your case it would be something like "_inheritFrom.skill".


Also keep in mind that you can not use polymorphism / inheritance for custom serializable classes. You may want to have a look at the script serialization documentation

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SHEePYTaGGeRNeP · Nov 28, 2017 at 08:22 AM 0
Share

I made some edits to answer some of your questions, but I'll answer them here too: BotPersonality is a serializable class.

 this._type = typeof(BotPersonality)

I changed the class BotPersonality to inherit from UnityEngine.Object, but that didn't resolve the issue. It still can't find the fields.

I'm not looking for help _inheritFrom.skill, just the normal object.`skill`. That'll be a problem for another day. So it would just be FindProperty("skill"), which is what happens with the looping over the fields.

avatar image Bunny83 SHEePYTaGGeRNeP · Nov 28, 2017 at 02:59 PM 0
Share

I thinks you still don't get my point. SerializedObject can only be used on actual serialized objects that Unity can serializes as standalone assets. Also you are not supposed to derive any class directly from UnityEngine.Object. The only classes you can use as base classes are $$anonymous$$onoBehaviour and ScriptableObject. ScriptableObjects need to be created with CreateInstance and must not be created with "new".


ScriptableObjects as well as $$anonymous$$onoBehaviours instances are always serialized on their own. The helper function (Utils.GetActualObjectForSerializedProperty) is not needed for classes that are implicitly derived from UnityEngine.Object. At access a referenced object (that is derived from $$anonymous$$onoBehaviour or ScriptableObject) you would simply use SerializedProperty.objectReferenceValue.


btw the article you've linked only works for custom serialized classes which are not derived from UnityEngine.Object (so not for $$anonymous$$onoBehaviours or ScriptableObjects). It also makes many assumptions that you only have 1 layer or nesting. To actually support any serialized property you would need something like it was posted over here-


However again this does not apply to properties which are actual serialized references (any reference to a UnityEngine.Object derived type).


About your simplified case: This should work just fine. However you should keep in $$anonymous$$d that you are creating a propertydrawer here. So it would be shown for the field "_inheritFrom" only. But ins$$anonymous$$d of showing anything from the referenced object you show the skill field of the containing class. This doesn't seem to make much sense. $$anonymous$$aybe you wanted to create a CustomEditor / Editor for your class? It's really hard for us to actually understand your goal and therefore your problem.


Finally I just realized that you use GUILayout elements inside the PropertyDrawer. This doesn't work. PropertyDrawers do not use the layout system. They get the rect they have to use as parameter. If you need more space for this property you have to override GetPropertyHeight and return how much space you need. However you have to use the GUI / EditorGUI functions inside a propertydrawer.

avatar image
0

Answer by SHEePYTaGGeRNeP · Nov 29, 2017 at 11:00 AM

I found out how to copy using Json. So I'll just use that instead of this (was my original plan anyway)

 "idName": "test2",
 "copyValuesFromId": "test",

And then I loop through all the fields

   foreach (BotPersonality bp in this.botPersonalities)
     {
     try
     if (String.IsNullOrEmpty(bp.copyValuesFromId) ||
         bp.copyValuesFromId.Equals("none", StringComparison.CurrentCultureIgnoreCase)) continue;
     BotPersonality copyFrom = this.botPersonalities.Find(x =>
         String.Equals(x.idName, bp.copyValuesFromId, StringComparison.CurrentCultureIgnoreCase));
     Assert.IsNotNull(copyFrom, "Id was not found in CopyValuesFromId " + bp.copyValuesFromId);
         foreach (FieldInfo fi in typeof(BotPersonality).GetFields(_BIND_FLAGS)
         .Where(x => x.IsDefined(typeof(DataMemberAttribute), false)))
     {
         // we only copy values that are null
         if (!ShouldCopyValue(fi, bp)) continue;
         fi.SetValue(bp, fi.GetValue(copyFrom));
     }
 }

Then ShouldCopyValue checks if it set to the default values

 private static bool ShouldCopyValue(FieldInfo fi, BotPersonality bp)
 {
     object value = fi.GetValue(bp);
     if (value == null)
         return true;
     Type t = value.GetType();
     if (t == typeof(int))
         return (int) value == Int32.MinValue;
     if (t == typeof(float))
         return ((float) value).AboutEqualTo(Single.MinValue);
     if (t.IsPrimitive)
         throw new Exception("Type " + t + " is not supported yet for bp: " + bp.idName);
     return false;
 }

Thank you anyway @bunny83 for all the explanations :)

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

73 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

CustomPropertyDrawer undoable properties 1 Answer

Property Drawer SerializedProperty is null 2 Answers

Custom inspector: How can I find out if a SerializedProperty will be drawn by a custom property drawer? 0 Answers

Inspector Overlapping Text Label at a Position 1 Answer

Bool field in CustomPropertyDrawer isn't clickable? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges