Search Unity

Get dirty flag from current open scene

Discussion in 'Scripting' started by Freaking-Pingo, Oct 2, 2014.

  1. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Hi there Uniteers, I am reposting this question from Unity Answer, because I have often gotten greater succese on the forums rather than Unity Answer.

    I am in need of a method of getting the dirty flag from the current open scene.
    I don't know of any integrated Unity method that allows me to do so, and I am not sure how I could achieve this using standard C# libraries.

    In short, what I am trying to do is to make an editor script which can inform multiple users on a team that a given person have made changes to the scene. This reason for this editor script is because occasionally multiple members on a team have modified the same scene, and when the scene is to be commited to either a Git repository or the Unity Asset Server, a merge conflict have been created. The editor script is then suppose to prematurely catch upcoming scene merge issues.
     
  2. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    An addition to my question, how does Unity handle altered files? Where is this information stored? In the RAM, in seperate file? I am very much interested in knowing the pibeline for saving content within Unity.

    Edit: Related to my first question, I have found a method which does some of the work.
    Code (CSharp):
    1. EditorApplication.hierarchyWindowChanged
    is an event which informs its listeners that a change have occured in the hiearchy. However, changes to GameObjects in the scene through the inspector do also enable the dirty flag, and I am not sure how to "listen" to changes to all inspector changes.
     
  3. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Update: By lurking a bit around, I have stumbled upon this variable:

    Code (CSharp):
    1. ActiveEditorTracker.sharedTracker.isDirty
    ActiveEditorTracker.sharedTracker.isDirty I have no idea what ActiveEditorTracker is, however its isDirty method is of interest. Whenever the Scene or Inspector values have changed, ActiveEditorTracker.sharedTracker.isDirty will return false, but if you recompile, IsDirty will return true, only for an update, and then return to false. If you haven't made changes to the Scene or any inspector values, isDirty will not return true upon recompile.

    This is close to what I want, but to be more specific of my requirements, I would like to know Instantly whenever the scene or inspector values have changed, but I am not sure whether this is possible.
     
  4. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    I would imagine that "ActiveEditorTracker" is used to track currently active "UnityEditor.Editor" instances. That is editors of selected objects shown in inspectors.

    Previously I was requesting that "ActiveEditorTracker.MakeCustomEditor" become documented so that I could use it in my asset:
    And fortunately this happened, but the function was relocated into the more suitable home "Editor.CreateEditor":
    With this function you could effectively create a custom inspector window.

    I do not think that this is what you are looking for though. This will just tell you if an asset has been flagged as dirty so that it will be automatically saved as soon as possible.

    I am wondering if the "AssetModificationProcessor" class would be helpful in your case:
     
  5. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    The AssetModoficationProcessor.OnWillSaveAssets(string[]) is only called upon the user actively saving the scene. But I am interested in finding or creating a callback / message when the user performs an active change to the scene which will cause it to be flagged and should be independent of the user saving the scene.
     
  6. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I am still struggling with this issue, because it doesn't really do what I want. AssetModoficationProcessor.OnWillSaveAssets(string[]) sure do register that your scene.unity is being saved, but it will become saved regardless of whether it have been changed or not. I would like an approach to identify whether the scene have been actually changed in either its hiearchy or its GameObjects within the scene.
     
  7. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Alright, I have taken another path. Apparently EditorUtility have a private method named EditorUtility.IsDirty(int instanceID); I have accesed the method through the use of reflection, and the following code can identify whether a prefab in your asset have been modified. However, the same code is not capable of identifying whether a scene have been modified:

    Getting the IsDirty state from a prefab. This code is working as intended.
    Code (CSharp):
    1.     void SomeFunction()
    2.     {
    3.         System.Type type = typeof(EditorUtility);
    4.         MethodInfo methodInfo = type.GetMethod("IsDirty", BindingFlags.Static | BindingFlags.NonPublic); // Get the method IsDirty  
    5.         Object obj = AssetDatabase.LoadAssetAtPath("Assets/Prefab.prefab", typeof(Object)); // Get the Prefab Object from the assets
    6.         int instanceID = obj.GetInstanceID(); // Get the Prefab Object's instance ID;
    7.         bool isDirty = (bool)methodInfo.Invoke(this, new System.Object[1]{instanceID}); // Execute the referenced method
    8.         if(isDirty)
    9.             Debug.Log ("Is dirty"); // States true when prefab is modified
    10.     }

    Trying to access a scene file in assets in the following code. This does not work as intended. IsDirty is never true even though you modify the scene by modifying the hiearchy / inspector values...
    Code (CSharp):
    1.     void SomeFunction()
    2.     {
    3.         System.Type type = typeof(EditorUtility);
    4.         MethodInfo methodInfo = type.GetMethod("IsDirty", BindingFlags.Static | BindingFlags.NonPublic); // Get the method IsDirty
    5.         Object obj = AssetDatabase.LoadAssetAtPath(EditorApplication.currentScene, typeof(Object)); // Get the Scene Object from the assets
    6.         int instanceID = obj.GetInstanceID(); // Get the Scene Object's instance ID;
    7.         bool isDirty = (bool)methodInfo.Invoke(this, new System.Object[1]{instanceID}); // Execute the referenced method
    8.         if(isDirty)
    9.             Debug.Log ("Is dirty"); // Is dirty is never called.
    10.     }
     
    Last edited: Oct 8, 2014
  8. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    I would imagine that EditorUtility.IsDirty is just reflecting whether or not EditorUtility.SetDirty has been used on an object.

    SetDirty marks an object as having changed so that it will be automatically saved when possible (or when user selects File | Save Project).

    I very much doubt that Unity marks the scene asset as dirty when changes have been made to it.
     
  9. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    That sure do sound plausible. I guess I'll have to find another approach then. When exiting Unity, a dialog do appear if you have made changes to the scene, and asks you whether to save or cancel your changes. There must exist some process within Unity that perhaps compares some checksum or read a bool or something which identifies whether there have been made changes to the scene. I am very much interested in finding an way to access this method. This is my first time using reflection to access non-public methods. Where can I find more information on these private methods and fields? Is there some sort of documentation for these methods somewhere, or do their exist forums / boards where these internal classes are discussed?
     
  10. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    If they are not public then its very unlikely that you will find any documentation!

    Also bare in mind that Unity is composed from two parts; the managed application and the native application. If the variable that you are hoping for only exists in the native part of the application then no amount of reflection will help you.
     
  11. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Well, the person who replied to my question on the Unity Answer forum sure had knowledge about some non documented features. I am wondering, how on earth he figured that out.

    But yeah, I do understand that what I am may not be possible.