Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
1
Question by greggman · Nov 25, 2014 at 01:49 AM · editor-scriptingeditorwindowundo

Editing and Undo for non-unity properties

How can handle undo for non-unity, not unity serialized properties?

Imagine I was making a .ini editor in unity using a custom EditorWindow. I read the ini file, for each [section] I make a Dictionary and for each key=value make an entry in a Dictionary themselves are in a Dictionary>.

In OnGui for each section I call EditorGUILayout.Folder and within each section I call EditorGUILayout.TextField for each key/value pair.

This all works. I can load an .ini file and I see all the fields. But, a bunch of things don't work and I'm really confused about what Unity expects.

  1. My data gets lost on every single call to OnGUI??? In other words I have something like this

      class MyWindow : EditorWindow
         {
           Dictionary<string, Dictionary<string, string> > m_sections;
    
           void OnGUI()
           {
             if (m_sections == null)
             {
               Debug.Log("new m_sections");   // This gets called constantly!!! WTF?!?!
               m_sections = new Dictionary<string, Dictionary<string, string>>();
             }
             ...
           }
         }
    
    
  2. How do I handle Undo?

I tried making class MyData that inherits from UnityEngine.Object and putting my Dictionary> instead it as a public field. That way I could call Undo.RecordObject. I can't imagine that will work but since I can't get past #1 above I have no idea.

Comment
Add comment · Show 4
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 greggman · Nov 25, 2014 at 02:41 AM 0
Share

sigh....this board ate parts of my post. I guess it doesn't like angle brackets in in-line code :(

avatar image Bunny83 · Nov 25, 2014 at 03:23 AM 0
Share

You shouldn't loose your data unless Unity does a recompile (because you edited a script outside of Unity) or you start / stop the game. What does "constantly" mean to you? OnGUI of an EditorWindow is only called when an event occurs.

Unity can't serialize Dictionaries at all, so you can't use Unity's Undo system. The Undo system is actually ment for undo user actions. If you just don't want to loose your data, store it in a serializable construct.

Could you be more precise what exactly you want to achieve? Do you just want to prevent your data get lost on serialization / deserialization or do you actually want register an undo action the user can revert?

avatar image greggman · Nov 26, 2014 at 01:13 AM 0
Share

What I mean is on every call to OnGUI m_sections is null. As for undo, I get that unity can't serialize dictionaries and I've removed them.

What I want to do is present a list of fields for the user to edit. Those fields are deter$$anonymous$$ed at runtime from an .ini file. If the user edits a field I want them to be able to undo their edit. They are global data (not tied to any GameObject or $$anonymous$$onoBehavior).

I found this blog post about serilization which actually doesn't work but lead to some progress. I found this wiki post which is out of date and doesn't work.

Do you know of any working samples of an EditorWindow that edit data not stored in a $$anonymous$$onoBehavior that support undo and persisting after closing and opening the EditorWindow?

avatar image Kiwasi · Nov 26, 2014 at 01:34 AM 0
Share

Does this help?

http://docs.unity3d.com/ScriptReference/Undo.html

2 Replies

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

Answer by Bunny83 · Nov 26, 2014 at 09:47 PM

To handle temporary data inside the editor that isn't lost when you close you editor windows, change the scene, change playmode or when scripts recompile you want to use a ScriptableObject. It's important to set the hideFlags to DontSave otherwise Unity would try to save it along with the scene. It would even mark the scene as dirty (modified) if you don't set the hideflags.

You usually want to use a singleton like pattern for this ScriptableObject. However keep in mind that static variables are also wiped when scripts are recompiled. So you have to use Resources.FindObjectsOfTypeAll to search for an existing (serialized) instance. Something like this:

 public class DataObject : ScriptableObject
 {
     private static DataObject m_Instance = null;
     public static DataObject Instance
     {
         get
         {
             if (m_Instance == null)
             {
                 var tmp = Resources.FindObjectsOfTypeAll<DataObject>();
                 if (tmp.Length > 0)
                     m_Instance = tmp[0];
                 else
                     m_Instance = ScriptableObject.CreateInstance<DataObject>();
                 m_Instance.hideFlags = HideFlags.DontSave;
             }
             return m_Instance;
         }
     }
 
     public string someSerializedData = "Hello World";
 }

Keep in mind that ScriptableObjects need it's own file where the file name matches the class name, just like MonoBehaviour scripts.

It's important to either always use the singleton property or get the reference in OnEnable and store it in a variable:

 // in your editor window
 DataObject data;
 void OnEnable()
 {
     data = DataObject.Instance;
 }
 void OnGUI()
 {
     data.someSerializedData = GUILayout.TextField(data.someSerializedData);
 }

Note: Unity also serialized private members of editor classes unless you put a NonSerialized attribute on it. So in this case here the reference to our DataObject instance which is stored in the "data" variable will survive playmode changes while the window is open.

Comment
Add comment · Show 2 · 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 greggman · Nov 26, 2014 at 11:28 PM 0
Share

Thanks for this. What if I want the data to be associated with the project? In other words I want it to survive across scenes the same as the data for the Physics$$anonymous$$anager or the Input$$anonymous$$anager etc..

avatar image Bunny83 · Nov 27, 2014 at 07:36 AM 0
Share

@greggman: In this case you have to save your ScriptableObject as asset using the AssetDatabase.CreateAsset. That way you can store the ScriptableObject as asset in the project. The TerrainData (which is also a ScriptableObject) does the same.

avatar image
-1

Answer by BMayne · Nov 26, 2014 at 02:19 AM

Hey There,

UnityEditor data does not serialize in any way at all.

Everything is temporary (editor stuff)

Whenever you view a editor class (inspector/window) you are looking at a brand new object. As soon as you close that window or change your selection (ie changing the inspector window) that editor window is tossed out with all that data that you think it saved. If you make a public bool it will stick around until you leave the window but if you come back it's a brand new window.

You are going to have to save the data yourself. What that comes down to is saving the data as XML or json (or whatever). You can then take this data and save it to EditorPrefs, a TextFile, a ScriptableObject, or the Userdata of the script itself. The choice is yours but each one has it's own advantages. If you are going simple just save your data to EditorPrefs (keep note this only saves on your computer).

The More You Know!

Unity uses a powerful library that is built into C# to make all these classes. It's called Reflection and the class they use is called Activator. This basically just makes a class on the fly just based on a type.

Comment
Add comment · Show 5 · 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 greggman · Nov 26, 2014 at 06:54 AM 0
Share

Thanks for that. I'm not sure what you mean by "Userdata of the script itself". I'm using a ScriptableObject to store my data. I'm using CreateInstance to create it. Undo works. But, closing the window I lose the data.

Here's the thing though. Even Unity's examples don't work? Here's a Unity talk on this issue. Here's a link to the samples from the talk. According to the talk the second example should work. So, download the samples, run any of them. Pick Window->SerializationXX where XX is one of the ones that's supposed to work. Try Serialization02 or Serializatoin07. Edit the fields, close the window, open the window, all data is gone. Having the data persist is specifically what the difference between Serliazation01 and Serialization02 or are supposed to show isn't it?

Any ideas how to fix it?

alt text

avatar image greggman · Nov 26, 2014 at 08:16 AM 0
Share

So I'm kind of maybe starting to get it. Unfortunately I'm still not sure. I need the data to persist past an EditorWindow being closed. And, I need Undo to persist as well. In other words, open EditorWindow, change "name" field from "abc" to "foo". Close window. Pick "undo". Field needs to go back to "abc" just like undoing a property in a component.

This doesn't work currently because the moment I close the EditorWindow all references to my data are gone so although their are entries in the undo stack (the undo menu shows an entry for undoing the last edit that happened in the editor window) that undo does nothing because there is no editor window and therefore no object to apply the undo or at least not one in my control

avatar image Ubiquit0us · Nov 26, 2014 at 01:31 PM 0
Share

The undo stack you are making does it effect only editor stuff or engine stuff too?

avatar image greggman · Nov 26, 2014 at 07:06 PM 0
Share

I'm not making an undo stack. I'm just calling Undo.RecordObject. I'm not sure what you mean by editor vs engine. The data only needs to exist in the editor at the moment.

avatar image Bunny83 · Nov 26, 2014 at 09:31 PM 0
Share

@B$$anonymous$$ayne: Your first statement is actually wrong. It's true that editor class aren't serialized to disk because that wouldn't make much sense. However Unity does serialize Editors, EditorWindows and everything else derived from UnityEngine.Object. Unity serializes everything before script compilation destroys all objects, loads the new assemblies and deserialize everything from the serialized data. That happens whenever Unity recompiles scripts or when changing gamemode.

Of course if you close an EditorWindow it's gone. You would have to use a ScriptableObject to store your data. I'll post an answer...

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

29 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

Related Questions

Weird bug when dragging object onto EditorGUILayout.ObjectField 0 Answers

Creating Editor 2D Animation Preview 2 Answers

mouseposition and clicks in editor sceneview 0 Answers

EditorWindow, Utility Popup, not using custom PropertyDrawers 0 Answers

EditorWindow reference to other scripts functions 0 Answers


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