Search Unity

PrefabUtility.SaveAsPefabAsset() crashes unity and results in a "broken" prefab

Discussion in 'Prefabs' started by NTNU_VR, Feb 14, 2019.

  1. NTNU_VR

    NTNU_VR

    Joined:
    Dec 6, 2018
    Posts:
    8
    I have made a script that takes a prefab, adds several components and then instantiate the new prefab in a scene in which runs in the editor. That script works as intended and the gameObject is instantiated as intended. Now I want to be able to instantiate more copies of the gameObject during runtime but cannot do it because it is not in the resources folder. For this reason (and some other) I want to, in addition to instantiating the gameObject, create a prefab in the resources folder.

    To create the prefab I use the PrefabUtility.SaveAsPrefabAsset(InstantiatedObject, Path), but when I run it Unity just spins and I cannot do anything other than force quit the application. The method did create a prefab at the given path, but when trying to open it an error is thrown:
    Code (CSharp):
    1. Opening Prefab Mode failed: The Prefab at 'Assets/LanguageVR/Resources/InteractableObjects/Et eple.prefab' is broken.
    2. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
    When I reopen Unity I am greeted with
    Code (CSharp):
    1. A default asset was created for 'Assets/LanguageVR/Resources/InteractableObjects/Et eple.prefab' because the asset importer crashed on it last time.
    2. You can select the asset and use the 'Assets -> Reimport' menu command to try importing it again, or you can replace the asset and it will auto import again.
    My code is here:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Valve.VR;
    5. using Valve.VR.InteractionSystem;
    6. using Photon.Pun;
    7. using UnityEditor;
    8.  
    9. //[ExecuteInEditMode]
    10. public class InteractableObject : MonoBehaviour
    11. {
    12.     [Tooltip("Click to instantiate the prefab in scene. Sometimes the old is not removed, manually delete it then")]
    13.     [SerializeField] private bool instantiatePrefab = false;
    14.  
    15.     [Tooltip("The word to appear over the object")]
    16.     [SerializeField] private new string name;
    17.  
    18.     // Changing font not working (out of the box)
    19.     //[Tooltip ("Font of name displayed in scene")]
    20.     //[SerializeField] private Font font;
    21.  
    22.     [Tooltip("The GameObject to be instantiated in the scene")]
    23.     [SerializeField] private GameObject physicalObject;
    24.  
    25.     [Tooltip("The audioclip associated with this object")]
    26.     [SerializeField] private AudioClip audioClip;
    27.  
    28.     private GameObject instantiatedObject;
    29.     private GameObject instantiatedTextObject;
    30.     private TextMesh textMesh;
    31.  
    32.     private AudioSource audioSource;
    33.  
    34.     void Awake()
    35.     {
    36.         instantiatedObject = transform.Find(physicalObject.name + "(Clone)").gameObject;
    37.         instantiatedTextObject = instantiatedObject.transform.Find("Text").gameObject;
    38.  
    39.         audioSource = GetComponent<AudioSource>();
    40.         textMesh = GetComponentInChildren<TextMesh>();
    41.     }
    42.  
    43.     void Update()
    44.     {
    45.         Throwable throwable = instantiatedObject.GetComponent<Throwable>();
    46.         if (throwable.IsAttached() && !instantiatedTextObject.activeSelf && throwable.IsMine())
    47.         {
    48.             instantiatedTextObject.SetActive(true);
    49.         }
    50.         else if (!throwable.IsAttached() && instantiatedTextObject.activeSelf)
    51.         {
    52.             instantiatedTextObject.SetActive(false);
    53.         }
    54.  
    55.         if (instantiatedTextObject.activeSelf)
    56.         {
    57.             Transform headTransform = ViveManager.Instance.head.transform;
    58.             instantiatedTextObject.transform.rotation = Quaternion.LookRotation(instantiatedTextObject.transform.position - headTransform.position);
    59.         }
    60.     }
    61.  
    62.     private void OnValidate()
    63.     {
    64.         if (instantiatePrefab)
    65.         {
    66.             InstantiatePhysicalObject();
    67.             InstantiateText();
    68.             SaveToResources();
    69.             instantiatePrefab = false;
    70.         }
    71.     }
    72.  
    73.     // Instansiates the given gameobject
    74.     private void InstantiatePhysicalObject()
    75.     {
    76.         // Destroy previous object if a new one is selected
    77.         if (instantiatedObject != null)
    78.         {
    79.             StartCoroutine(Destroy(instantiatedObject));
    80.         }
    81.  
    82.         instantiatedObject = Instantiate(physicalObject);
    83.         instantiatedObject.transform.parent = this.transform;
    84.         instantiatedObject.transform.localPosition = Vector3.zero;
    85.         instantiatedObject.AddComponent<Rigidbody>();
    86.  
    87.         int numberOfChildren = instantiatedObject.transform.childCount;
    88.         if (numberOfChildren == 0)
    89.         {
    90.             if (!instantiatedObject.GetComponent<MeshCollider>())
    91.             {
    92.                 instantiatedObject.AddComponent<MeshCollider>();
    93.             }
    94.             instantiatedObject.GetComponent<MeshCollider>().convex = true;
    95.         }
    96.         else
    97.         {
    98.             for (int i = 0; i < numberOfChildren; i++)
    99.             {
    100.                 GameObject child = instantiatedObject.transform.GetChild(i).gameObject;
    101.                 if (!child.GetComponent<MeshCollider>())
    102.                 {
    103.                     child.AddComponent<MeshCollider>();
    104.                 }
    105.                 child.GetComponent<MeshCollider>().convex = true;
    106.             }
    107.         }
    108.  
    109.         AudioSource instantiatedAudioSource = instantiatedObject.AddComponent<AudioSource>();
    110.         instantiatedAudioSource.clip = audioClip;
    111.         instantiatedAudioSource.playOnAwake = false;
    112.  
    113.  
    114.         Throwable throwable = instantiatedObject.AddComponent<Throwable>();
    115.         instantiatedObject.AddComponent<Interactable>();
    116.         instantiatedObject.AddComponent<VelocityEstimator>();
    117.         PhotonView photonView = instantiatedObject.AddComponent<PhotonView>();
    118.  
    119.         photonView.ObservedComponents = new List<Component>();
    120.         photonView.ObservedComponents.Add(throwable);
    121.         photonView.OwnershipTransfer = OwnershipOption.Takeover;
    122.         photonView.Synchronization = ViewSynchronization.UnreliableOnChange;
    123.     }
    124.  
    125.     private void InstantiateText()
    126.     {
    127.         instantiatedTextObject = new GameObject("Text");
    128.         instantiatedTextObject.transform.parent = instantiatedObject.transform;
    129.         instantiatedObject.transform.localPosition = Vector3.zero;
    130.  
    131.         textMesh = instantiatedTextObject.AddComponent<TextMesh>();
    132.  
    133.         textMesh.text = name;
    134.         textMesh.transform.localPosition = Vector3.zero;
    135.         textMesh.transform.localScale = Vector3.one * 0.01f;
    136.         textMesh.fontSize = 100;
    137.         textMesh.anchor = TextAnchor.MiddleCenter;
    138.         //textMesh.font = font;
    139.     }
    140.  
    141.     private void SaveToResources()
    142.     {
    143.         PrefabUtility.SaveAsPrefabAsset(instantiatedObject, "Assets/LanguageVR/Resources/InteractableObjects/" + textMesh.text + ".prefab");
    144.     }
    145.  
    146.     // Can only destroy gameobjects in OnValidate using a coroutine
    147.     IEnumerator Destroy(GameObject go)
    148.     {
    149.         yield return new WaitForEndOfFrame();
    150.         DestroyImmediate(go);
    151.     }
    152. }
    The instantiation happens when a checkbox is ticked in the editor, which first instantiates the gameObject and adds several components, then instantiates a textMesh adding it to the newly instantiated gameObject, before finally saving it to resources in SaveToResources().

    Am I using PrefabUtility.SaveAsPrefabAsset() wrong, or is this a bug?
    I am using 2018.3.3f1, but am updating to 3.5 now and will comment if the problem is gone in the update.

    EDIT: Just updated to 3.5 and the problem persists.
     
    Last edited: Feb 14, 2019
  2. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Crashes are always bugs. Unity should never crash. We'll appreciate a bug report using the bug reporter in Unity.

    In the future, no need to ask in the forum if a crash is a bug. It is. Just go right ahead and report it so we can track it and look into it. Thanks.
     
  3. NTNU_VR

    NTNU_VR

    Joined:
    Dec 6, 2018
    Posts:
    8
    Sent a bug report. For the interested: the bug can be boiled down to trying to make a prefab of an instantiated gameObject.
     
    runevision likes this.
  4. Deleter

    Deleter

    Joined:
    Dec 21, 2012
    Posts:
    23
    for people having this kind of issue, i deleted the .meta by backuping as a .meta_old (i could have deleted it also) then i came back in my Editor now the prefab opens well (it was corrupted and unable to open the prefab before this) i think Unity regenerating the .meta can solve some issues (my editor crashed just before this)