Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Prevent Prefab field from being changed in Prefab instance?

Discussion in 'Immediate Mode GUI (IMGUI)' started by fwalker, May 2, 2013.

  1. fwalker


    Feb 5, 2013
    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


    Mar 8, 2010
    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


    Nov 24, 2010
    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;
    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;
    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);
    28.             // Now that we have the asset, grab the component.
    29.             var prefab = prefabGameObject.GetComponent<ImmutableInInstance>();
    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. }
    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


    Feb 8, 2016

    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