Search Unity

How to modify prefabs by code?

Discussion in 'Prefabs' started by strich, Dec 1, 2018.

  1. strich

    strich

    Joined:
    Aug 14, 2012
    Posts:
    278
    I've been trying to batch update a large number of prefabs and since the new preset and nesdted prefab systems have been introduced there seem to be conflicting or confusing ways to achieve this. Sample code below:

    Code (CSharp):
    1. [MenuItem("GC/Bulk Updates/Update Mesh Rdr to Preset")]
    2. public static void UpdateMeshRdrToPreset()
    3. {
    4.     var preset = AssetDatabase.LoadAssetAtPath<Preset>("Assets/Presets/MeshRenderer_Default.preset");
    5.     var assets = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Bundles/Rooms" })
    6.         .Select(a => ( AssetDatabase.GUIDToAssetPath(a), AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(a)))).ToList();
    7.     assets.ForEach(t =>
    8.     {
    9.         (var path, var prefab) = t;
    10.  
    11.         var mrs = prefab.GetComponentsInChildren<MeshRenderer>().ToList();
    12.         foreach (var mr in mrs)
    13.         {
    14.             preset.ApplyTo(mr);
    15.         }
    16.  
    17.         EditorUtility.SetDirty(prefab);
    18.     });
    19.     AssetDatabase.SaveAssets();
    20. }
    I can tell that this does successfully reserialize the prefabs via git diff. But the preset isn't being applied. For isolation purposes you can replace the preset.ApplyTo function with any other direct property modification and it still won't work.
     
  2. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    443
    @strich

    (Sorry about the delay :) )

    That said, it does work fine for me. Which version of Unity are you using?
     
  3. strich

    strich

    Joined:
    Aug 14, 2012
    Posts:
    278
    I've done a little more digging. Here is some new info:
    Base Model Import
    |_Wall 0 (Prefab variant of base model import)
    ..|_Wall 1 (Prefab variant of Wall 0)

    Wall 0 gets successfully updated with the preset values. Wall 1 doesn't change and instead now shows the previous default values as an override.

    Maybe ApplyTo() isn't issuing overrides?
     
  4. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    443
    Ah yes that would make sense. You could try adding
    Code (CSharp):
    1. PrefabUtility.RecordPrefabInstancePropertyModifications(mr)
    after applying the preset
     
  5. strich

    strich

    Joined:
    Aug 14, 2012
    Posts:
    278
    It applies for some but not all. I cannot for the life of me determine why. Could it be that some children (Wall 1-99) get applied, then the base (Wall 0), then more children (Wall 1-99). The children before and after then have differing results?
     
  6. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    443
    I am not certain what is happing. I will have to recreate your setup here and have a look at it.