// Compile all hierarchical prefabs public static void CompileAllHierarchicalPrefabs() { // Ensure the compilation directory exist Directory.CreateDirectory(GetCompiledHierarchicaPrefabFolderGlobalPath()); // Empty it DestroyAllCompiledHierarchicalPrefabs(); // Will keep track of the dirty instance model // Because if we set the resource to dirty too soon it will only save the root and let the children in the scene List <HierarchicalPrefabInstance> oDirtyHierarchicalPrefabInstanceModels = new List <HierarchicalPrefabInstance>(); // loop through all the hierarchical prefabs in the resources bool bAtLeastOnePrefabCompiled = false; foreach (string rAssetPath in AssetDatabase.GetAllAssetPaths()) { // Is this a prefab? GameObject rGameObjectPrefab = AssetDatabase.LoadAssetAtPath(rAssetPath, typeof(GameObject)) as GameObject; if (rGameObjectPrefab != null) { // Try to grab a hierarchical prefab HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = rGameObjectPrefab.GetComponent <HierarchicalPrefabInstance>(); if (rHierarchicalPrefabInstanceModel != null) { // If need to be compile if (rHierarchicalPrefabInstanceModel.CanBeInstantiatedAtRuntime) { // Compile it rHierarchicalPrefabInstanceModel.Compile(); // Add it to the dirty list oDirtyHierarchicalPrefabInstanceModels.Add(rHierarchicalPrefabInstanceModel); bAtLeastOnePrefabCompiled = true; } } } } // loop through all the hierarchical prefabs in the resources foreach (HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel in oDirtyHierarchicalPrefabInstanceModels) { // Set dirty EditorUtility.SetDirty(rHierarchicalPrefabInstanceModel); } // Compilation is up to date NestedPrefabEditorSettings.MustCompile = false; if (bAtLeastOnePrefabCompiled) { // Notify the user of the compilation completion Debug.Log("Compilation Successful!"); } else { DisplayNothingToCompileMessage(); } }
// On inspector gui public override void OnInspectorGUI() { base.OnInspectorGUI(); HierarchicalPrefabInstance rHierarchicalPrefabInstance = target as HierarchicalPrefabInstance; rHierarchicalPrefabInstance.CanBeInstantiatedAtRuntime = EditorGUILayout.Toggle("Can Be Instantiated", rHierarchicalPrefabInstance.CanBeInstantiatedAtRuntime); }
// Convert into hierarchical prefab public static HierarchicalPrefabInstance ConvertIntoHierarchicalPrefab(GameObject a_rGameObjectToConvert) { // Add the hierarchical prefab if not there HierarchicalPrefabInstance rHierarchicalPrefabInstance = NestedPrefabComponentUtility.GetOrCreate <HierarchicalPrefabInstance>(a_rGameObjectToConvert); // Clear the hierarchy from the prefab and add instantiator to respawn them when needed TrimHierarchicalPrefab(a_rGameObjectToConvert.transform); return(rHierarchicalPrefabInstance); }
// Save as hierarchical prefab public static bool SaveAsHierarchicalPrefab(GameObject a_rGameObjectToSave, string a_rSavePath) { // Convert to hierarchical prefab HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = NestedPrefabEditorUtility.ConvertIntoHierarchicalPrefab(a_rGameObjectToSave); // The prefab to save into Object rPrefabObjectToSaveInto = AssetDatabase.LoadAssetAtPath(a_rSavePath, typeof(Object)); // Check if the hierarchical prefab is cyclic if (IsHierarchicalPrefabInstanceCyclic(rHierarchicalPrefabInstanceModel, rPrefabObjectToSaveInto)) { Debug.LogError("You can't create cyclic hierarchy!"); rHierarchicalPrefabInstanceModel.RevertToHierarchicalPrefab(); return(false); } // Save into a prefab at save path if (rPrefabObjectToSaveInto == null) { rPrefabObjectToSaveInto = PrefabUtility.CreateEmptyPrefab(a_rSavePath); } else { // If an object replace a prefab copy the replaced prefab version number // To the one replacing if (rPrefabObjectToSaveInto != rHierarchicalPrefabInstanceModel.HierarchicalPrefab) { // Try to get the hierarchical prefab instance model of the soon to de replaced prefab GameObject rPrefabToBeReplacedGameObject = NestedPrefabEditorUtility.GetPrefabGameObject(rPrefabObjectToSaveInto); if (rPrefabToBeReplacedGameObject != null) { HierarchicalPrefabInstance rHierarchicalPrefabInstanceModelToBeReplaced = rPrefabToBeReplacedGameObject.GetComponent <HierarchicalPrefabInstance>(); if (rHierarchicalPrefabInstanceModelToBeReplaced != null) { // Copy the version number of the instance to be replaced rHierarchicalPrefabInstanceModel.CopyVersionNumber(rHierarchicalPrefabInstanceModelToBeReplaced); } } } } // Notify model instance of it's saving rHierarchicalPrefabInstanceModel.OnSaveModelInstanceBeforePrefabReplacement(PrefabUtility.GetPrefabObject(rPrefabObjectToSaveInto)); #if BEFORE_UNITY_4_3 EditorUtility.ReplacePrefab(a_rGameObjectToSave, rPrefabObjectToSaveInto, ReplacePrefabOptions.ConnectToPrefab); #else PrefabUtility.ReplacePrefab(a_rGameObjectToSave, rPrefabObjectToSaveInto, ReplacePrefabOptions.ConnectToPrefab); #endif // Compilation is not up to date NestedPrefabEditorSettings.MustCompile = true; return(true); }
// Ensure the prefab validity : // Either a functionning hierarchical prefab or a clean classic prefab. public static void EnsurePrefabValidity(GameObject a_rPrefabGameObjectToCheck) { // If the prefab is still valid don't bother updating it HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = a_rPrefabGameObjectToCheck.GetComponent <HierarchicalPrefabInstance>(); if (rHierarchicalPrefabInstanceModel == null || rHierarchicalPrefabInstanceModel.IsValid() == false) { // If it's not a hierarchical prefab, ensure that the prefab is clean NestedPrefabEditorUtility.DisconnectResourceFromHierarchicalPrefab(a_rPrefabGameObjectToCheck); } }
// On Hierarchical prefab update public void OnHierarchicalPrefabUpdate(HierarchicalPrefabInstance a_rHierarchicalInstanceCaller) { if (this != null) { // if the connection with the hierarchical prefab is broken if (HierarchicalPrefab == null) { // If the prefab is still there and has just been replaced if (m_rPrefabObject != null) { // Try to grab the nested prefab data from the potential instantiator NestedPrefabData rNestedPrefabData = TryGrabNestedPrefabData(); // Replace the current object by an instance of the new prefab GameObject rNewInstance = PrefabUtility.InstantiatePrefab(NestedPrefabEditorUtility.GetPrefabGameObject(m_rPrefabObject)) as GameObject; HierarchicalPrefabInstance rNewHierarchicalPrefabInstance = rNewInstance.GetComponent <HierarchicalPrefabInstance>(); // If nested if (rNestedPrefabData != null && rNewHierarchicalPrefabInstance != null && transform.parent != null) { rNewHierarchicalPrefabInstance.ReloadNestedPrefabData(rNestedPrefabData); // Change the parent without changing the local transform information NestedPrefabUtility.ChangeParentAndKeepSameLocalTransform(rNewHierarchicalPrefabInstance.transform, transform.parent); } else { Vector3 f3LocalScaleSave = rNewInstance.transform.localScale; rNewInstance.transform.parent = transform.parent; rNewInstance.transform.localPosition = transform.localPosition; rNewInstance.transform.localRotation = transform.localRotation; rNewInstance.transform.localScale = f3LocalScaleSave; } // Auto destruction Editor.DestroyImmediate(gameObject); } } else { // Revert to hierarchical prefab //RevertToHierarchicalPrefab(); if (this == a_rHierarchicalInstanceCaller) { // if it's the updated instance we just redeploy the hierarchy DeployHierarchy(); } else { // Revert to hierarchical prefab RevertToHierarchicalPrefab(); } } } }
// Try to reinstantiate a hierarchical prefab public bool TryToReloadData(HierarchicalPrefabInstance a_rHierarchicalPrefabInstance) { // Try to find a prefab data corresponding to the hierarchical prefab NestedPrefabData rNestedPrefabData = TryGrabNestedPrefabData(a_rHierarchicalPrefabInstance.gameObject); if (rNestedPrefabData != null) { // Load its property modifications rNestedPrefabData.LoadModifications(a_rHierarchicalPrefabInstance.gameObject); return(true); } return(false); }
// Is a nested prefab public static bool IsNestedPrefab(GameObject a_rChild, GameObject a_rRoot) { HierarchicalPrefabInstance rHierarchicalPrefabInstance = a_rChild.GetComponent <HierarchicalPrefabInstance>(); if (rHierarchicalPrefabInstance != null) { return(rHierarchicalPrefabInstance.HierarchicalPrefab != null); } else { Object rPrefabOfChild = PrefabUtility.GetPrefabObject(a_rChild); Object rPrefabOfRoot = PrefabUtility.GetPrefabObject(a_rRoot); return(a_rChild.transform.parent != null && rPrefabOfChild != null && rPrefabOfChild != rPrefabOfRoot); } }
// Force the intern prefab update to avoid instance override to get in the way private void ForcePrefabInformationUpdate() { GameObject rHierarchicalPrefab = HierarchicalPrefab; if(rHierarchicalPrefab != null) { HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = rHierarchicalPrefab.GetComponent<HierarchicalPrefabInstance>(); if(rHierarchicalPrefabInstanceModel != null) { m_iHierarchicalPrefabVersionNumber = rHierarchicalPrefabInstanceModel.m_iHierarchicalPrefabVersionNumber; m_rPrefabObject = rHierarchicalPrefabInstanceModel.m_rPrefabObject; m_rCompiledHierarchicalPrefab = rHierarchicalPrefabInstanceModel.m_rCompiledHierarchicalPrefab; m_bSceneInstance = true; } } }
// Trim the hierarchical prefab public static void TrimHierarchicalPrefab(Transform a_rTreeToTrimRoot) { // Begin by the Hierarchical prefab instance leaf // Go all the way down first, then climb and trim recursively foreach (Transform rChildTransform in a_rTreeToTrimRoot) { // Wait to be at the hierarchy trim to actualy execute the trim TrimHierarchicalPrefab(rChildTransform); } // If we are on a hierarchical prefab transform it HierarchicalPrefabInstance rHierarchicalPrefabInstance = a_rTreeToTrimRoot.GetComponent <HierarchicalPrefabInstance>(); if (rHierarchicalPrefabInstance != null) { // Clear the hierarchy from the prefab and add instantiator to respawn them when needed ReplacePrefabInHierarchyByInstantiator(rHierarchicalPrefabInstance.gameObject); } }
// Summary : Instantiate a Prefab GameObject // Note : Same as the GameObject.Instantiate (You can use this method as replacement) // But add the capability to instantiate the compiled version of a Hierarchical Prefab // Return : The created instance public static GameObject Instantiate(GameObject a_rPrefabGameObject, Vector3 a_f3Position, Quaternion a_oRotation) { DisplayCompilationNotUpToDateWarningIfNeeded(); // Try to get the hierarchical component of the prefab game object HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = a_rPrefabGameObject.GetComponent <HierarchicalPrefabInstance>(); // If it's a hierarchical prefab if (rHierarchicalPrefabInstanceModel != null) { // Instantiate the compiled hierarchic prefab return(rHierarchicalPrefabInstanceModel.InstantiateCompiledVersion(a_f3Position, a_oRotation)); } // If it's a normal prefab else { // Instantiate the prefab return(GameObject.Instantiate(a_rPrefabGameObject, a_f3Position, a_oRotation) as GameObject); } }
// Has prefab changed? private bool HasPrefabChanged() { // If the resource has changed GameObject rHierarchicalPrefab = HierarchicalPrefab; if(rHierarchicalPrefab != null) { HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = rHierarchicalPrefab.GetComponent<HierarchicalPrefabInstance>(); if(rHierarchicalPrefabInstanceModel != null && m_iHierarchicalPrefabVersionNumber != rHierarchicalPrefabInstanceModel.m_iHierarchicalPrefabVersionNumber) { return true; } } else { // The resource can have been overrided return true; } return false; }
// Compile the hierarchical prefab public void Compile() { // Instantiate a copy of us GameObject rHierarchicalPrefabToBeCompiledGameObject = PrefabUtility.InstantiatePrefab(gameObject) as GameObject; // Force the hierarchy to deploy HierarchicalPrefabInstance rHierarchicalPrefabToBeCompiled = rHierarchicalPrefabToBeCompiledGameObject.GetComponent <HierarchicalPrefabInstance>(); rHierarchicalPrefabToBeCompiled.DeployHierarchy(); // Disconnect from the hierarchical prefab world NestedPrefabEditorUtility.DisconnectFromHierarchicalPrefab(rHierarchicalPrefabToBeCompiledGameObject); // Ensure the compilation directory exist Directory.CreateDirectory(Application.dataPath.Replace("Assets", "") + mc_oCompiledHierarchicalPrefabFolderPath); // Prefab object into which to save Object rPrefabObject; if (m_rCompiledHierarchicalPrefab == null) { // Ensure we have a unique save path string oSavingPath = mc_oCompiledHierarchicalPrefabFolderPath + "/" + rHierarchicalPrefabToBeCompiledGameObject.name + ".prefab"; oSavingPath = AssetDatabase.GenerateUniqueAssetPath(oSavingPath); // Save it into a prefab rPrefabObject = PrefabUtility.CreateEmptyPrefab(oSavingPath); } else { rPrefabObject = PrefabUtility.GetPrefabObject(m_rCompiledHierarchicalPrefab); } GameObject rPrefabGameObject = PrefabUtility.ReplacePrefab(rHierarchicalPrefabToBeCompiledGameObject, rPrefabObject); // Link the instance model to the prefab m_rCompiledHierarchicalPrefab = rPrefabGameObject; // Destroy the instance Editor.DestroyImmediate(rHierarchicalPrefabToBeCompiledGameObject); }
// On save public void OnSaveModelInstanceBeforePrefabReplacement(Object a_rPrefabObject) { // Save the prefab object for recuperation (mainly to react after an other object override our prefab) m_rPrefabObject = a_rPrefabObject; // Increment version IncrementHierarchicalPrefabVersion(); // Clear the scene instance flag m_bSceneInstance = false; // Conserve the compiled prefab GameObject rPrefabGameObject = HierarchicalPrefab; if(rPrefabGameObject) { HierarchicalPrefabInstance rHierarchicalPrefabInstance = rPrefabGameObject.GetComponent<HierarchicalPrefabInstance>(); if(rHierarchicalPrefabInstance != null) { m_rCompiledHierarchicalPrefab = rHierarchicalPrefabInstance.m_rCompiledHierarchicalPrefab; } } }
// Is the instance nested (directly or not) on an other instance of the same prefab? private bool IsNestedInHierarchicalInstanceOfSamePrefab() { // Climb up the hierarchy and test if there is a hierarchical instance of the same prefab Transform rCurrentParent = transform.parent; while(rCurrentParent != null) { // Is the parent a hierarchical instance? HierarchicalPrefabInstance rParentHierarchicalPrefabInstance = rCurrentParent.GetComponent<HierarchicalPrefabInstance>(); if(rParentHierarchicalPrefabInstance != null) { // Is it an instance of the same prefab if(rParentHierarchicalPrefabInstance.PrefabObject == PrefabObject) { return true; } } // Climb up one level rCurrentParent = rCurrentParent.parent; } return false; }
// Get all selected hierarchical prefabs public static List <HierarchicalPrefabInstance> GetSelectedHierarchicalPrefabInstanceModels() { // The selected hierarchical prefab List <HierarchicalPrefabInstance> oSelectedHierarchicalPrefabInstanceModels = new List <HierarchicalPrefabInstance>(); // loop through the selected game object foreach (GameObject rSelectedGameObject in Selection.gameObjects) { // Try to get the prefab game object GameObject rPrefabGameObject; if (EditorUtility.IsPersistent(rSelectedGameObject)) { rPrefabGameObject = rSelectedGameObject; } else { rPrefabGameObject = PrefabUtility.GetPrefabParent(rSelectedGameObject) as GameObject; } rPrefabGameObject = PrefabUtility.FindPrefabRoot(rPrefabGameObject); if (rPrefabGameObject != null) { // If it's a hierarchical prefab HierarchicalPrefabInstance rHierarchicalPrefabInstanceModel = rPrefabGameObject.GetComponent <HierarchicalPrefabInstance>(); if (rHierarchicalPrefabInstanceModel != null) { // Avoid duplicate if (oSelectedHierarchicalPrefabInstanceModels.Contains(rHierarchicalPrefabInstanceModel) == false) { oSelectedHierarchicalPrefabInstanceModels.Add(rHierarchicalPrefabInstanceModel); } } } } return(oSelectedHierarchicalPrefabInstanceModels); }
// Update selection private bool UpdateSelection() { // Save the current selection ESelectionMode eSelectionModeLast = m_eSelectionMode; GameObject rSelectedGameObjectLast = m_rSelectedGameObject; HierarchicalPrefabInstance rSelectedHierarchicalPrefabInstanceLast = m_rSelectedHierarchicalPrefabInstance; // Update the selected game object m_rSelectedGameObject = Selection.activeGameObject; // Update the selection mode if (Application.isPlaying) { m_eSelectionMode = ESelectionMode.InPlayMode; m_rSelectedGameObject = null; } else if (m_rSelectedGameObject == null) { m_eSelectionMode = ESelectionMode.None; } else if (EditorUtility.IsPersistent(m_rSelectedGameObject)) { m_rSelectedHierarchicalPrefabInstance = m_rSelectedGameObject.GetComponent <HierarchicalPrefabInstance>(); if (m_rSelectedHierarchicalPrefabInstance == null) { m_eSelectionMode = ESelectionMode.IsAResourceButNotAHierarchicalPrefab; } else { m_eSelectionMode = ESelectionMode.IsAHierarchicalPrefabResource; } } else { m_rSelectedHierarchicalPrefabInstance = m_rSelectedGameObject.GetComponent <HierarchicalPrefabInstance>(); if (m_rSelectedHierarchicalPrefabInstance == null) { m_eSelectionMode = ESelectionMode.IsNotAHierarchicalPrefabInstance; } else { if (m_rSelectedHierarchicalPrefabInstance.HierarchicalPrefab == null) { m_eSelectionMode = ESelectionMode.IsAHierarchicalInstancePrefabWithoutResource; } else { m_eSelectionMode = ESelectionMode.IsAConnectedHierarchicalInstancePrefab; } } } bool bMustCompileLast = m_bMustCompile; m_bMustCompile = NestedPrefabEditorSettings.MustCompile; // Check if there was change if (eSelectionModeLast != m_eSelectionMode || rSelectedGameObjectLast != m_rSelectedGameObject || rSelectedHierarchicalPrefabInstanceLast != m_rSelectedHierarchicalPrefabInstance || bMustCompileLast != m_bMustCompile) { return(true); } else { return(false); } }
// Is Cyclic? public static bool IsHierarchicalPrefabInstanceCyclic(HierarchicalPrefabInstance a_rTestedHierarchicalPrefabInstance, Object a_rPrefabToSaveInto) { return(IsHierarchicalPrefabTreeContainAnInstantiatorOf(a_rTestedHierarchicalPrefabInstance.transform, PrefabUtility.GetPrefabObject(a_rPrefabToSaveInto))); }
// Notify the other instances of update public static void NotifyInstancesOfHierarchicalPrefabUpdate(Object a_rHierarchicalPrefab, HierarchicalPrefabInstance a_rHierarchicalInstanceCaller) { // Loop through the instances of this prefab and notify them foreach (HierarchicalPrefabInstance rHierarchicalPrefabInstance in GetAllInstancesOfHierarchicalPrefab(a_rHierarchicalPrefab)) { rHierarchicalPrefabInstance.OnHierarchicalPrefabUpdate(a_rHierarchicalInstanceCaller); } }
// Copy version number public void CopyVersionNumber(HierarchicalPrefabInstance a_rHierarchicalPrefabInstanceToCopy) { m_iHierarchicalPrefabVersionNumber = a_rHierarchicalPrefabInstanceToCopy.m_iHierarchicalPrefabVersionNumber; }
// Clean project button action private void CleanProjectButtonAction() { HierarchicalPrefabInstance.ClearAllCompiledHierarchicalPrefabs(); }
// Compile All button action private void CompileAllButtonAction() { HierarchicalPrefabInstance.CompileAllHierarchicalPrefabs(); }
// Compile Selected button action private void CompileSelectedButtonAction() { HierarchicalPrefabInstance.CompileSelectedHierarchicalPrefabs(); }