Trying to access properties inside a class with SerializedProperty not working

Hi there, I’m trying to access the following class:

[Serializable]
    public class BasicItemProperties
    {
        public string itemName;
        public ItemType itemType;
        public Sprite itemSprite;
        public string itemDescription;
    }

With this custom editor code:

BasicItemProperties temp = basicItemProperties.objectReferenceValue
                    as object as BasicItemProperties;

                ItemType itemTypeTest = temp.itemType;

I was able to get this working when temp was a ScriptableObject (though the cast was slightly different), but now that temp is a class that isn’t a Unity.object I’m getting errors.

I’m sure there must be a way to access the properties of a class from a custom editor but I just can’t seem to get it working.

Any tips on this?

Hi,

I’m not sure if I understood you right, but here it goes.

Say you have a MB class with a field of type Item, named item. You can get it like this in your custom editor:

var item = serializedObject.FindProperty("item");

Your Item might look something like this (doesn’t make much sense, but I hope it doesn’t matter):

[System.Serializable]
public class Item
{
   // some fields
   public string itemName;
   public FoodValues food;
}

To get a field in your Item from your custom editor, you can then do something like this:

// Get food
var food = item.FindPropertyRelative("food");

And then you can draw it for example:

EditorGUILayout.PropertyField(food, true);

That’s because SerializedProperty.objectReferenceValue returns a UnityEngine.Object.

BasicItemProperties is not a UnityEngine.Object.

That property doesn’t return you class for the same reason ‘floatValue’ doesn’t return you class. That property isn’t for that.

Unfortunately SerializedProperty doesn’t have a property to return plain old objects. It’s just a quark of how Unity designed their serialization engine.

3 Likes

Thanks for the response, I’ll try this out. In this example, would var food be of type FoodValues?

I don’t need to draw the properties, they are being drawn fine by the editor, but I’m trying to compare them and so I need to make sure I get the actual property type if that makes sense. So in your example I need food to be of type FoodValues.

Hey thanks for the info! So there’s no straightforward way of getting a non-Unity object from a serialized field?

I can’t try the above method right now suggested by eses, but if that works that looks pretty good! The string references aren’t ideal but I really only need to do it once or twice in this editor.

Depdends on what you need to do.

If you need to access serialized members of the subobject, eses suggestion will work.

So say your script was:

public class MyScript : MonoBehaviour
{
    public BasicItemProperties Props;
}

Then your editor for MyScript to access Props would be:

var props = serializedObject.FindProperty("Props");
var itemNameProp = props.FindPropertyRelative("itemName");
string itemName = itemName.stringValue;

If you’re in a PropertyDrawer for BasicItemProperties, you won’t have to find the “Props” property since the OnGUI method passes you that:

But if you needed to access non-serialized members (like methods/functions or fields/properties marked as nonserialized). Then you’d have to get a ref to your MyScript and just read from it directly:

var script = serializedObject.targetObject as MyScript;
var val = script.Props.SomeUnserializedProperty;

If you were in a PropertyDrawer again, and you didn’t know that we were a member of MyScript. Well it gets complicated then since you’d have to reflect it. Here’s an old thread talking about it:

Maybe I’m doing this wrong but none of these options are working for me. I’ll look more closely at the thread linked by @lordofduct though, maybe I can find a solution there.

Just to reiterate I’m trying to get the ItemType inside of the BasicItemProperties from an editor script.

Here is my ItemType class:

[CreateAssetMenu(fileName = "New Item Type", menuName = "Inventory Assets/Item Type")]
    public class ItemType : ScriptableObject
    {
        [SerializeField] ItemCategory itemCategory;

        public ItemCategory ItemCategory { get => itemCategory; }
    }

It’s mostly just a simple SO. and it is held inside of the BasicItemProperties class:

[Serializable]
    public class BasicItemProperties
    {
        public string itemName;
        public ItemType itemType;
        public Sprite itemSprite;
        public string itemDescription;
    }

I’m not trying to expose the ItemType in the inspector. That’s already being done with the following code:

EditorGUILayout.PropertyField(basicItemProperties, new GUIContent("Basic Item Properties"));

What I’m trying to do is actually get the ItemType so I can use it. Exactly like I’m doing with this other class ItemTypeOrganizer in the following code:

ItemTypeOrganizer organizer = (ItemTypeOrganizer)itemTypeOrganizer.objectReferenceValue;

                organizer.SomeMethod();

And here is the ItemTypeOrganized script I’m working on:

[CreateAssetMenu(fileName = "New ItemType Organizer", menuName = "Inventory Assets/ItemType Organizer")]
    public class ItemTypeOrganizer : ScriptableObject
    {
        public void SomeMethod()
        {
               // Do stuff
        }
    }

I take it this works because ItemTypeOrganized inherits from SO and so it’s a type of Unity object, where BasicItemProperties is not. Still, there’s gotta be a way to get one the properties inside of the class right?

Did you already figure this out? I’m not exactly sure what the problem is, but I think you can get access to your ItemType like this (from your custom editor), pretty much what lordofduct said already:

// Your MB with basic item properties
var script = serializedObject.targetObject as YourMBClassNameHere;

// Your basic item properties item type
var itemType = script.basicItemProperties.itemType;

// get something from item type
var value = itemType.someValue;

You’re exactly right, this works perfectly. I mist have misunderstood the earlier post and tried to access the properties from the wrong target object. Your comments on the code were very helpful thank you!

I did also find that this works:

ItemType itemType = (ItemType)basicItemProperties.FindPropertyRelative("itemType").objectReferenceValue;

So both ways seem to return the right value for this property.

I also read through some of this linked thread:

https://discussions.unity.com/t/581352

At the bottom there’s a suggestion by Dr-Nick that seems interesting.

It’s using a new feature called boxedValue: https://docs.unity.cn/2022.1/Documentation/ScriptReference/SerializedProperty-boxedValue.html

I wonder if that would work. I’m hesitant to upgrade my game to a beta version of Unity, not sure just how stable they are, but maybe once it becomes a full release I’ll try that out.

It seems like it could work, through I’m not 100% sure. Not super familiar with handling data in these Editor scripts, I haven’t done that much honestly.

For now, the solutions suggested here work great though! Thanks everyone!

2 Likes

Right. I haven’t used the new boxedValue feature myself since I didn’t use Unity for quite some time now ^^. Though I’ve seen people recognise it and from what I’ve heard it seems to fill exactly that gap we had for years. So it makes the old cumbersome reflection madness kinda obsolete. Though it seems it still has some limitations. We have to do some more testing I guess.