Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

How can a PropertyDrawer receive onAfterDeserialize and onBeforeSerialize events?

Discussion in 'Scripting' started by TomNCatz, Apr 3, 2020.

  1. TomNCatz

    TomNCatz

    Joined:
    Jan 6, 2015
    Posts:
    22
    I am writing a property drawer that needs to be notified when just before the serialization pass and just after the deserialization pass. Unsurprisingly, inheriting from ISerializationCallbackReceiver in the property drawer does not seem to get this functionality.

    Is there a way to get similar events for the property drawer?

    I know that the SerializeField attribute probably uses some sort of internal workaround that is not available to us, but I am looking for very similar functionality.

    I have largely used property drawers to make my classes less dependent on their containing class so that they can be used without needing to do a whole bunch of setup. Being able to control serialization at the property drawer level takes this up a notch. Currently I have a property drawer that handles serialization and deserialization through buttons that show in the inspector. This means that you have to keep track in your head of when unity saves and loads data, instead of unity just notifying you.

    Basically, I want to set it up so some non-MonoBehaviour classes so that they know how to serialize their own data when used inside a MonoBehaviour.

    Does anyone have thoughts on this?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,141
    So PropertyDrawer's don't exist unless the inspector is showing. So it won't necessarily receive the event as it's not necessarily instantiated at that moment.

    SerializeField is just an attribute. When serialization occurs, Unity just reflects all the fields off an object. And it serializes it if:
    1) Is a serializable type
    2) Is public OR marked with the SerializeFieldAttribute.

    I don't know off the top of my head of any hook into the serialization event outside of ISerializationCallbackReceiver. You could of course create your own static event on the types that you're creating, then fire them in the ISerializationCallbackReceiver. BUT this means that you have to boiler plate this code for each and every type, and also means that there's the added overhead of all of these types having this interface on it that you'd likely want to remove on build... you of course could use the compiler symbols to do that... but then what of the types that need it at runtime too.

    I don't know... just spit-balling. I'm not fully understanding what it is you're attempting to accomplish though. What would you be doing with these PropertyDrawer's that can receive this event anyways? Is it so you can create attributes for fields that control how they serialize to other fields? Like maybe you have a Dictionary, and an array of KeyValuePair, and you attribute the Dictionary pointing it at the KeyValuePair array, and the PropertyDrawer knows to ToArray the dict into the array field?

    Cause I mean... if that's what you want... well a big issue I see is that the PropertyDrawer won't exist at runtime and therefore the deserialization logic won't exist since it's in the editor code.

    I could think maybe implementing a mixin system that could work this way... but again, I'm work on assumption/speculation at this point since I don't know your design/goal.
     
  3. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,233
    ISerializationCallbackReceiver should be in the class you are setting up the property drawer for. The serialization system will call OnBeforeSerialize() and OnAfterDeserialize() on the objects it is serializing/deserializing that inherit that interface.

    What exactly are you doing that you would need this in the property drawer?
     
  4. TomNCatz

    TomNCatz

    Joined:
    Jan 6, 2015
    Posts:
    22
    I have lots of uses of it, but my current usage is an abstract list. Each item knows how to save and load itself both in and out of a list. Like I said, I have two buttons I can press that serialize it into a format unity can handle, and those are displayed in a property drawer. I would, however, like the property drawer to know when to save and load on its own.

    The list is only edited in the inspector when you have it selected in the inspector. The rest of the time it just assumes that it will need to load itself to from the serialized data.

    As stated, manually clicking on the buttons I have exposed in the property drawer works, it just requires you keep in your head what the serialization state of the object is instead of unity managing it for you.

    I was hoping that serialized properties would be notified in some way when they are getting serialized or deserialized and that I could hook into that in some fashion. This would reduce developer error since they can trust that it is saving their actions like any other field would.
     
  5. TomNCatz

    TomNCatz

    Joined:
    Jan 6, 2015
    Posts:
    22
    Do OnBeforeSerialize() and OnAfterDeserialize() get called on classes that are not MonoBehaviours? I am trying not to have the class require its parent to make changes to support it.
     
  6. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,233
    Any serializable class that inherits that interface. That is why its an interface and not just built into the base class UnityEngine.Object.
     
  7. TomNCatz

    TomNCatz

    Joined:
    Jan 6, 2015
    Posts:
    22
    I for some reason did not think that would work. I ran a quick test and it seems to do what I needed.

    Thank you very much!