Search Unity

  1. Full schedule for #UniteBerlin is now available! Featuring talks on our roadmap, hands-on labs and much more! Check it out!
    Dismiss Notice
  2. Unity 2018.1 has arrived! Read about it here
    Dismiss Notice
  3. Scriptable Render Pipeline improvements, Texture Mipmap Streaming, and more! Check out what we have in store for you in the 2018.2 Beta.
    Dismiss Notice
  4. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  5. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Prevent Prefab field from being changed in Prefab instance?

Discussion in 'Extensions & OnGUI' started by fwalker, May 2, 2013.

  1. fwalker

    fwalker

    Joined:
    Feb 5, 2013
    Posts:
    63
    Is there a way to prevent a field in a prefab from being changed in the inspector of the prefab instance? I still want to be able to change it in the prefab itself.
     
  2. Wahooney

    Wahooney

    Joined:
    Mar 8, 2010
    Posts:
    226
    I made an editor once that would only draw parts of itself when the prefab is selected, so I could make changes to some fields in the scene, but base, world-wide changes had to be made in the prefab.

    Just check that the target object that you have selected is a prefab or a prefab instance and guard your editor GUI calls accordingly.

    PS this just hides the ability for an end user to modify these values, and you should probably guard those values even further with a [HideInInspector] attribute.

    Hope this helps.
     
  3. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    Sorry for necro-posting, but I needed something very similar to this a while back and it took me a little bit of effort to find a solution. So I thought I would share.

    There are two ways of doing this: first one is easy but requires a bit of code, and the second one is even easier but requires a bit of money.

    First solution is to use the OnValidate to reset the value of a field if it's being changed from a prefab instance and not the prefab itself. It goes something like this:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEngine.Assertions;
    4.  
    5. public class ImmutableInInstance : MonoBehaviour
    6. {
    7.     // This field should only be changeable from
    8.     // the prefab itself and not through any of
    9.     // its instances.
    10.     public float cannotBeChangedInInstance;
    11.  
    12.     void OnValidate()
    13.     {
    14.         // This code only makes sense in the Editor, so
    15.         // better make double sure it runs only in the
    16.         // editor. Might be unnecessary since OnValidate
    17.         // only runs in the editor as well.
    18. #if UNITY_EDITOR
    19.         // Is this an instance of a prefab?
    20.         if (PrefabUtility.GetPrefabType(gameObject) == PrefabType.PrefabInstance)
    21.         {
    22.             // It is! Then get the prefab asset.
    23.             var prefabObject = PrefabUtility.GetPrefabParent(gameObject);
    24.             Assert.IsNotNull(prefabObject);
    25.             var prefabGameObject = prefabObject as GameObject;
    26.             Assert.IsNotNull(prefabGameObject);
    27.  
    28.             // Now that we have the asset, grab the component.
    29.             var prefab = prefabGameObject.GetComponent<ImmutableInInstance>();
    30.  
    31.             // And finally, reset the value in this instance by
    32.             // grabbing the original value from the component
    33.             // in the prefab.
    34.             cannotBeChangedInInstance = prefab.cannotBeChangedInInstance;
    35.         }
    36. #endif
    37.     }
    38. }
    39.  
    The field cannotBeChangedInInstance will still look like it's editable from the inspector, but any attempt to change the value from an instance will reset to the value from the prefab. Not the most elegant but it was good enough for our needs.

    The second, even easier option is to buy the Odin Inspector and Serializer and just use either DisableInPrefabInstancesAttribute or the HideInPrefabInstancesAttribute (or possibly both) on the field in question.

    Another option is to write a custom inspector as @Wahooney suggested, but I personally prefer to work on the actual project at hand rather than waste my time trying to understand the arcane arts of Editor Alchemy (which does sound like a great title for a book on the subject).
     
  4. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    106
    Hey,

    we also have a solution others may be interested in.

    Basically it pseudo flows like this:
    0)in your script on the field you don't want to be applied add the attribute [PreventApply]

    0b)subscribe to the UnityEditor.PrefabUtility.prefabInstanceUpdated Delegate with FunctionA
    0c)Load a (json) file (DefaultData), which will hold some data about your prefab and prevented change fields

    1)When a prefab is applied FunctionA will run
    2a)if YourPrefab GUID does not exist in DefaultData go through all components and their Reflect to their serialized fields and look for any fields that have the attribute [PreventApply], If one does add the data with a field identifier to DefaultData
    2b) Otherwise, Go through all components and serlized fields looking for fields that have the [PreventApply] Then Find the correct field inside DefaultData and set to the value which it was mapped to

    Please note, this method only works for non-object types