- Home /
EditorWindow member serialization in OnDisable
So I've recently run into an issue with transitioning an EditorWindow instance from editor mode to play mode. I want to set a serializable member to a value so that when play mode button is pressed (which reloads the Mono DLLs), the value of the member is set back to what it was in editor mode. I've read this blog post, which explained quite a bit about how it's done, and how to overcome some standard cases.
The problem is that I need to set the member at the end of the EditorWindow's edit mode lifespan, and as far as I'm aware, that means it has to be done in OnDisable(). However, it seems that the editor-to-play serialization happens sometime before OnDisable(), so any changes made to the member in that function aren't a part of serialization.
Here is the scenario at its simplest:
using UnityEditor;
using UnityEngine;
public class ExampleWindow : EditorWindow
{
static ExampleWindow()
{
// prints out whatever libraries are reloaded
System.AppDomain.CurrentDomain.AssemblyLoad +=
(object sender, System.AssemblyLoadEventArgs args) =>
{
Debug.Log("Assembly loaded: " + args.LoadedAssembly.FullName);
};
}
[MenuItem("MenuItem/Example")]
public static void Init()
{
GetWindow(typeof(ExampleWindow));
}
void OnEnable()
{
Debug.Log("OnEnable: " + x);
x = 66;
}
void OnDisable()
{
Debug.Log("OnDisable");
x = 42;
}
[SerializeField]
int x;
}
When the window is first created, OnEnable is called - x is logged as 0, then x gets set to 66. If play mode is entered while this instance is still open, OnDisable gets called - x is set to 42. The assemblies are then reloaded for play mode, so OnEnable gets called again - but instead of logging 42, x is 66. This is what leads me to believe that serialization has happened prior to OnDisable.
I was curious what you all had to make of this, and what I could do to get it working appropriately. Is there a function I'm not aware of that I could use to get this member set near the end of a lifespan but before serialization? If not, any other solutions? I'd like to avoid something redundant like setting in Update().
The example I posted was just a simplification of my problem.
In reality, here's the situation: Throughout the life of the EditorWindow, I'm maintaining and updating a complex data structure. The design of this structure makes it impossible to derive ScriptableObject; I tried it a several days ago, and I ended up scrapping the changes because I reached a brick wall, mainly because ScriptableObject's factory-style creation didn't mix well with what was already in-place.
So, in the last few days, I've optioned to create a memento from the object, which has the bare $$anonymous$$imum info about the complex object. I can then reconstruct my complex object from the memento at a later time. (See: memento pattern). The memento is what derives from ScriptableObject.
I thought this would work excellently when switching from edit mode to play mode - just extract a memento from my complex object in OnDisable(), save it to a serializable member, then recreate my structure in OnEnable() with the serialized member.
But, of course, I ran into the problem I have now - serialization seems to happen before OnDisable().
I was under the same impression about the flow, so I've modified the code above a bit, because sanity checks are always nice. I've even made it so that it prints out when an assembly is reloaded.
According to the output, our assumption is correct, so I'm still under the impression that Unity must serialize sometime before OnDisable.
OnLostFocus sounds like a good idea, since there really is no way to NOT call it when pressing Play. I'll try that and see how it pans out.
Hey, using OnLostFocus seemed to do the trick. I'm not sure why I didn't think of it before; I guess I just got wound up with the problem.
I'll give credit where it's due if you convert your comment to an answer.
Answer by Loius · Jul 08, 2013 at 10:54 PM
I haven't encountered your specific issue, but I've been coding around the thought that the flow is:
{User clicks Play}, then OnDisable, then OnEnable
I may be wrong; have you tried Debug.Logs to be sure your OnEnable write isn't overwriting your OnDisable?
Perhaps OnLostFocus and OnDestroy might fit your model better?
I recently found the EditorApplication.playmodeStateChanged event which is what I think the OP was looking for. It's called right before serialization, it seems.
Answer by Jamora · Jul 08, 2013 at 08:45 PM
I hope by redundant you mean setting the values every frame, because mine involves a flag check in OnGUI in your EditorWindow...
If you just need different value for runtime and editor mode, then a simple hack could work:
void OnGUI(){
if(Application.isPlaying != modeFlag){
modeFlag = Application.isPlaying;
if(modeFlag)
x = 42;
else
x = 66;
}
GUILayout.Label(x.ToString());
Repaint();
}
This would skip serialization completely.
Yes, that is what I mean by redundant.
I'm not referring to having a different value in play mode than in edit mode. I've added some additional commentary to my post to help clarify the situation.
Your answer
Follow this Question
Related Questions
SerializedProperty and PropertyField NullReference 1 Answer
Inconsistancies between EditorWindow and MonoBehaviour Serialization 2 Answers
Custom Editor window loses values on play. 1 Answer
How do serialized Texture2D fields store and manage Texture2D data pulled from a dll ? 1 Answer
Multiple Cars not working 1 Answer