• 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
1
Question by Glurth · Oct 23, 2017 at 09:26 PM · editortypeserializedpropertyobject referenceobjectfield

ObjectField functions ignoring parameter

I’m attempting to use the SerialzedProperty versions of the EditorGUILayout.ObjectField function to display a custom ScriptableObject, but it ignores me when I try to specify the object's type.

  • Background/details:

The custom ScriptableObject implements inheritance; a BaseClass (derived from ScriptableObject), with two other classes derived from that (DerivedClassA, and DerivedClassB).

In my editor code, the SerializedProperty I'm trying to draw references a member of the sample MonoBehaviour. This member is declared (but not instantiated) as a BaseClass.

  • Main issue:

In my editor code, I will use some logic to determine if I want to allow the user to select one or the other of the derived classes. (In the sample below, I just display them all, as tests)

Unfortunately, when I use the SerializedProperty version of the ObjectField function, that takes a Type as a parameter, the type parameter is ignored.

  • Other tests:

However, If I used the Object (rather than the SerializedProperty) versions of the ObjectFiled function, it DOES use the Type parameter properly.

  • Question:

Am I doing something wrong? Why does the ObjectField function ignore the provided parameter when I use the SerializedProperty version?

  • Code:

Here is my test project’s code. It is the editor file, at the bottom, that contains the problematic function calls. You can use the menu items to create test objects of each derived class, in the project folder, if you want to try it out. I'm also attaching a "package" (zipped), so no need to copy/paste, if you want to try it out.

link text

BaseClass.cs

 using UnityEngine;
 
 public class BaseClass : ScriptableObject {
 
     public int anInt;
 }

DerivedClassA.cs

 using UnityEditor;
 
 public class DerivedClassA : BaseClass {
 
     public float aFloat;
 
     
     [MenuItem("GameObject/MyCategory/DerivedClassA Object", false, 10)]
     static void CreateCustomDerivedClassA(MenuCommand menuCommand)
     {
         // Create a custom game object
         DerivedClassA instance = DerivedClassA.CreateInstance<DerivedClassA>();
         AssetDatabase.CreateAsset(instance, "Assets/MyDerivedClassA.mat");
 
     }
 }

DerivedClassB.cs

 using UnityEditor;
 
 public class DerivedClassB : BaseClass {
 
     public string aString = "a";
     [MenuItem("GameObject/MyCategory/DerivedClassB Object", false, 10)]
     static void CreateCustomDerivedClassA(MenuCommand menuCommand)
     {
         // Create a custom game object
         DerivedClassB instance = DerivedClassB.CreateInstance<DerivedClassB>();
         AssetDatabase.CreateAsset(instance, "Assets/MyDerivedClassB.mat");
 
     }
 }

HoldingMono.cs

 using UnityEngine;
 
 public class HoldingMono : MonoBehaviour {
     public BaseClass baseClass;
 }

HoldingMonoEditor.cs

 using UnityEngine;
 using UnityEditor;
 
 [CustomEditor(typeof(HoldingMono))]
 public class HoldingMonoEditor : Editor
 {
 
     SerializedProperty baseClassProperty;
 
     void OnEnable()
     {
         baseClassProperty = serializedObject.FindProperty("baseClass");
     }
 
     public override void OnInspectorGUI()
     {
         EditorGUILayout.ObjectField(baseClassProperty, typeof(DerivedClassA));// allows selection of any BaseClass objects, and shows the type BaseClass when empty
         EditorGUILayout.ObjectField(baseClassProperty, typeof(DerivedClassB));// allows selection of any BaseClass objects, and shows the type BaseClass when empty
 
         baseClassProperty.objectReferenceValue=EditorGUILayout.ObjectField(new GUIContent("DerivedClassA"),baseClassProperty.objectReferenceValue, typeof(DerivedClassA),false);// allows selection of only DerivedClassA objects, and shows the type DerivedClassA whgen empty
         baseClassProperty.objectReferenceValue = EditorGUILayout.ObjectField(new GUIContent("DerivedClassB"), baseClassProperty.objectReferenceValue, typeof(DerivedClassB), false);// allows selection of only DerivedClassB objects, and shows the type DerivedClassB when empty
 
     }
 }


objectfields.zip (2.2 kB)
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

1 Reply

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Bunny83 · Oct 23, 2017 at 09:53 PM

Yes, the Type parameter is in fact ignored. Have a look at this:

 private static void ObjectFieldInternal(Rect position, SerializedProperty property, Type objType, GUIContent label, GUIStyle style)
 {
     int controlID = GUIUtility.GetControlID(EditorGUI.s_PPtrHash, FocusType.Keyboard, position);
     position = EditorGUI.PrefixLabel(position, controlID, label);
     bool allowSceneObjects = false;
     if (property != null)
     {
         Object targetObject = property.serializedObject.targetObject;
         if (targetObject != null && !EditorUtility.IsPersistent(targetObject))
         {
             allowSceneObjects = true;
         }
     }
     EditorGUI.DoObjectField(position, position, controlID, null, null, property, null, allowSceneObjects, style);
 }

As you can see the "objType" parameter is not used here. It should have been passed instead of the "null" infront of the property parameter in the last line. The first null is an UnityEngine.Object reference. The method DoObjectsField is actually used by all ObjectField methods. So either "property" is null or that object reference is null.

So you can probably call it a bug. Note that i don't use the latest Unity version but that's how it looks like in "Unity 5.6.1f1". The SerializedProperty version of ObjectField is actually relative new. It already existed as internal methods but those didn't have a Type argument. So it's probably a copy&paste error. File a bugreport and get it fixed in a year ^^

Comment
Add comment · Show 11 · 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 Bunny83 · Oct 23, 2017 at 09:56 PM 0
Share

The reason why the "UnityEngine.Object" version works is that it directly uses DoObjectField like this:

 public static Object ObjectField(Rect position, Object obj, Type objType, bool allowSceneObjects)
 {
     int controlID = GUIUtility.GetControlID(EditorGUI.s_ObjectFieldHash, FocusType.$$anonymous$$eyboard, position);
     return EditorGUI.DoObjectField(EditorGUI.IndentedRect(position), EditorGUI.IndentedRect(position), controlID, obj, objType, null, null, allowSceneObjects);
 }

avatar image Glurth · Oct 23, 2017 at 10:48 PM 0
Share

Thanks, Bunny! Bug submission complete: https://fogbugz.unity3d.com/default.asp?961878_20mllpnjoe3393ne @Adam-$$anonymous$$echtley FYI

avatar image Bunny83 Glurth · Oct 24, 2017 at 12:55 AM 0
Share

As a temporary workaround you could use this reflection solution. Unfortunately it's not possible to create a delegate for the method (to improve performance and avoid garbage) since that "ObjectFieldValidator" is an internal type and you can't create a delegate that would be compatible with the methods parameter list.

Though I cached as much as possible. Since Unity's Rect struct has a Set method we can even avoid boxing the position all the time by simply creating a delegate for a single boxed value that is reused each time. The only thing that can't be avoided is the single boxed "int" for the controlID as there's no way to set a boxed integer value to another value without re-boxing the value again.

$$anonymous$$aybe it got a bit too far with the optimisations, but it seems to work ^^

avatar image Glurth Bunny83 · Oct 24, 2017 at 01:57 AM 0
Share

So that solution basically replaces the bugged version, and invokes the internal DoObjectField itself? Nice!

Show more comments
Show more comments

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.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

95 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 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

Make a PropertyField() for a Texture2D SerializedProperty looking like an ObjectField() 2 Answers

How to Find Assets of the Same Type in Editor Script 1 Answer

Access another objects property in an editor script 1 Answer

Serialized string doesn't get saved in edtior 0 Answers

Generate Script in Editor Script and GetType() returns null. 3 Answers

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges