Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 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 Qubitz · May 22, 2018 at 02:02 AM · c#editor-scriptingserializationattributedrawer

Serializable settings for custom PropertyDrawer

Setup

I have constructed a custom PropertyDrawer for a custom PropertyAttribute to create something similar to the RangeAttribute, but for all data types. My PropertyDrawer requires an int to draw the inspector UI because 'the int' dictates the UI. In most other PropertyDrawers you can assume the data type under the attribute (i.e. float, Vector2, etc.) and have the PropertyDrawer read and write to that data type.

Question

However, I can't assume the data type because I'd like this attribute to be available for all data types. Therefore, I can't store 'the int' in the method mentioned above. I need a way to serialize 'the int' so that it persists through assembly reload and Unity closing. Got any ideas?

Attempts

  • Creating a serializable ScriptableObject class to hold 'the int' and reference that in either my custom PropertyDrawer or PropertyAttribute.

  • Throw around [SerializeField] and [Serializable] attributes on 'the int' and PropertyDrawer and PropertyAttribute classes

  • Try to learn more about serialization, but PropertyDrawers or PropertyAttributes are never mentioned.

    Example

     public class MyBehavior : MonoBehaviour
     {
         [My]
         public Vector2 data1;
     
         [My(2)]
         public SomeSerializedClass data2;
     }
     
     [AttributeUsage(AttributeTargets.Field)]
     public class MyAttribute : PropertyAttribute
     {
         public int value;  // what needs to be serialized
     
         public MyAttribute(int startingValue = 1)
         {
             value = startingValue;
         }
     }
     
     [CustomPropertyDrawer(typeof(MyAttribute))]
     public class MyDrawer : PropertyDrawer
     {
         private int value;  // or maybe this can be serialized instead?
     
         public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
         {
             var attr = attribute as MyAttribute;
             value = attr.value;
     
             // Here I need `value` to be persistent upon Unity open/close
             //   and script reloading, hence the issue.
             value = EditorGUI.IntSlider(position, value, 1, 2);
     
             // ... draw `property` based on `value` ...
         }
     }
    
    

value must be serialized within MyAttribute or MyDrawer due to value's independence on property's underlying type.


Please let me know what I need to clarify. Thanks for any help! :)

Comment
Add comment · Show 2
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 NoDumbQuestion · May 22, 2018 at 03:02 AM 0
Share

You have to add System.Serializable on top of the class scriptableObject name too. And you have to set Custom editor for ScriptableObject to dirty too. In newer Unity version, you have to use Undo property for each serialize variables when you set it.

But most people use Odin Inspector to make custom Property or Drawer now because it save lots of time coding custom Editor. $$anonymous$$aybe you want to try to learn a thing or 2.

avatar image Qubitz NoDumbQuestion · May 22, 2018 at 08:08 AM 0
Share

Thanks for the quick response. I have tried making the ScriptableObject serializable to no avail. What do you mean when you say "you have to set Custom editor for ScriptableObject to dirty too"? I'm only using the ScriptableObject to hold data, I don't see the need for a custom editor.

1 Reply

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

Answer by Adam-Mechtley · May 22, 2018 at 08:12 AM

I'm not 100% clear what you're trying to do, but depending what meets your needs, I would recommend one of the following (in order of decreasing recommendation):

  1. Use property.propertyType to find out what type of field you're drawing and respond accordingly

  2. Use PropertyDrawer.fieldInfo to find out exactly what field you're drawing and respond accordingly

  3. Use PropertyDrawer.attribute to find out metadata for the field you're drawing and respond accordingly

To clarify case 3, it would look something like this:

 public enum MyCustomMetadata { Something, SomethingElse, AndSoOn }

 public class MyCustomAttribute : PropertyAttribute {
     public readonly MyCustomMetadata CustomMetadata;
     public MyCustomAttribute(MyCustomMetadata customMetadata) {
         CustomMetadata = customMetadata;
     }
 }

 public class MyBehavior : MonoBehaviour {
     [SerializeField, MyCustomAttribute(MyCustomMetadata.Something)]
     private int m_MyIntField;
 }

 [CustomPropertyDrawer(typeof(MyCustomAttribute))]
 public class MyCustomDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
         MyCustomMetadata customMetadata = (attribute as MyCustomAttribute).CustomMetadata;
         // do something based on value of customMetadata
     }
 }

Comment
Add comment · Show 3 · 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 Qubitz · May 23, 2018 at 03:51 AM 0
Share

I added some example code to give a better idea of the problem.

  • I can't pursue solution 1 or 2 because the attribute is for any and all fields including other custom serializable classes.

  • Solution 3 only provides a constant to reference (I would need a variable), but gave me an idea to pass a variable into the attribute by reference, but that's also impossible :(.

Hope my example can lead to some other ideas. Thanks a ton!

avatar image Adam-Mechtley Qubitz · May 23, 2018 at 07:09 AM 1
Share

Thanks for adding more context! I think the best (bad) approach here will depend on the behavior you ultimately want.

  • If the serialized data is specific only to the field type (i.e. all decorated SomeSerializedClass fields will share the same setting), then probably use EditorPrefs.

  • If the serialized data is specific to each target object instance (i.e. each SomeSerializedClass on each $$anonymous$$yBehavior might have a different setting) then you probably want to save the serialized data to another field on the target object.

In the second case, you basically need to supply some string to your attribute that lets you find the serialized data of interest. For example:

 class $$anonymous$$yAttribute : PropertyAttribute {
     public readonly string settingPath;
     public $$anonymous$$yAttribute(string settingPath) {
         this.settingPath = settingPath;
     }
 }
 class $$anonymous$$yBehavior : $$anonymous$$onoBehaviour {
     [SerializeField, $$anonymous$$y("m_Vector2Setting")]
     private Vector2 m_Vector2;
     [SerializeField, HideInInspector]
     private int m_Vector2Setting;
 }

 class $$anonymous$$yDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
         var settingPath = (attribute as $$anonymous$$yAttribute).settingPath;
         // this is naive and assumes the field being drawn isn't nested in some struct/class/array path
         // a more complete approach would walk one level up property.propertyPath if needed and use property.FindPropertyRelative
         var setting = property.serializedObject.FindProperty(settingPath);
     }
 }

avatar image Qubitz Adam-Mechtley · May 24, 2018 at 06:49 AM 1
Share

Omg! Passing a string through the attribute constructor is a great idea! Totally forgot about Unity's overuse of strings and the FindProperty method. I just tested it and it works great :D. Thanks!


To anyone else: make sure the property you're referencing in the string is public facepalm

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

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

SerializedProperty and PropertyField NullReference 1 Answer

Can you force editor scripts to serialize their data,How to serialize fields in an editor script 0 Answers

Custom Editor window loses values on play. 1 Answer

Multiple scripts reference to the same SerializeField 1 Answer

Variable data removed on play. 1 Answer


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