Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Custom Editor & new Prefabs - how to setup overrides?

Discussion in 'Prefabs' started by Dreamteck, May 9, 2019.

  1. Dreamteck

    Dreamteck

    Joined:
    Feb 12, 2015
    Posts:
    214
    I'm using custom editors for quite a few MonoBehaviour scripts and not all of them are using the SerializedProperties as there are just some things that I require some custom logic for.

    The problem comes when I create a prefab (2018.3) with such MonoBehaviour and put an instance of it in the scene. If I try to modify references to objects inside this prefab, upon clicking "Play", these references will be reverted to whatever the prefab was set to. That is understandable because I'm not using SerializedObject and SerializedProperty but is there still a way to tell the prefab system that these properties have been overriden even though I have set their value directly in the editor?
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    3,856
    Code (csharp):
    1. EditorUtility.SetDirty(yourScript);
    2. EditorSceneManager.MarkSceneDirty(yourScript.gameObject.scene);
    or call Undo.RecordObject(yourScript) before you make the changes.
     
  3. Dreamteck

    Dreamteck

    Joined:
    Feb 12, 2015
    Posts:
    214
    Thanks! I was already calling Undo.RecordObject but it seems that for the new prefab system, I also need to call EditorUtility.SetDirty

    Cheers!
     
  4. Roni92pl

    Roni92pl

    Joined:
    Jun 2, 2015
    Posts:
    261
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    686
    Roni92pl, thanks for your note. I was beating my head on this.

    Why is this so complicated? "Oh, gotta mark an Undo.RecordObject point." "Oh, gotta also mark each component dirty that you touch." "Oh, gotta also ALSO mark the scene dirty, which may be the prefab environment or the actual scene." "Oh, gotta also ALSO ALSO mark the prefab instance property modifications for each component you touch, but does this apply if the script is not run on a prefab instance, dunno, let's just cross our fingers (oh also check if we are in play mode)."

    Code (CSharp):
    1. #ifdef UNITY_EDITOR
    2.         {
    3.             if (UnityEditor.EditorApplication.isPlaying)
    4.                 return;
    5.             UnityEditor.Undo.RecordObject(gameObject, "descriptive name of this operation");
    6.             /// make changes here
    7.             var prefabStage =
    8.                 UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
    9.             if (prefabStage != null)
    10.             {
    11.                 UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(
    12.                     prefabStage.scene);
    13.             }
    14.             else
    15.             {
    16.                 UnityEditor.EditorUtility.SetDirty(gameObject);
    17.                 UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(this);
    18.                 UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
    19.             }
    20.         }
    21. #endif // UNITY_EDITOR
    22.  
    Maybe the experimental prefabstageutility part is not necessary; I found that example before I found someone simply calling it on any scene regardless.

    Yep, confirmed that prefabStage.scene == gameObject.scene so it's ever so slightly less complicated without that.

    Code (CSharp):
    1. #ifdef UNITY_EDITOR
    2.         {
    3.             if (UnityEditor.EditorApplication.isPlaying)
    4.                 return;
    5.             UnityEditor.Undo.RecordObject(gameObject, "descriptive name of this operation");
    6.             /// make changes here
    7.             UnityEditor.EditorUtility.SetDirty(gameObject);
    8.             UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(this);
    9.             UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
    10.         }
    11. #endif // UNITY_EDITOR
    12.  
     
    Last edited: May 24, 2019
    awesomedata and Dreamteck like this.
  6. Roni92pl

    Roni92pl

    Joined:
    Jun 2, 2015
    Posts:
    261
    Afaik you don't need to manualy SetDirty Object if you earlier called RecordObject on it.
    Edit: yup, docs confirm it:
    https://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html
     
  7. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    735
    It sometimes seems as if Unity is built solely for Unity's engineers, doesn't it?


    There really needs to be a wrapper class for all of this functionality to show that it is indeed linked in how it is used.

    With the advent of nested prefabs and now ECS representations of objects in the scene, how can anyone be expected to just intuit the required steps to modify scene objects through code on their own?