public override void OnInspectorGUI() { if (m_TextStyle == null) { m_TextStyle = "ScriptText"; } Hash128 dependencyHash = AssetDatabase.GetSourceAssetFileHash(m_AssetGUID); if (m_LastDependencyHash != dependencyHash) { CachePreview(); m_LastDependencyHash = dependencyHash; } bool enabledTemp = GUI.enabled; GUI.enabled = true; if (m_TextAsset != null) { Rect rect = GUILayoutUtility.GetRect(m_CachedPreview, m_TextStyle); rect.x = 0; rect.y -= 3; rect.width = GUIClip.visibleRect.width + 1; GUI.Box(rect, m_CachedPreview, m_TextStyle); } GUI.enabled = enabledTemp; }
public static PrefabAssetInfo GetState(string guid) { var id = GetPrefabAssetIdentifier(guid); var cachedPrefabAssetInfo = s_StateCache.GetState(id); if (cachedPrefabAssetInfo == null) { return(null); // not cached yet } var currentPrefabSourceFileHash = AssetDatabase.GetSourceAssetFileHash(guid); if (currentPrefabSourceFileHash != cachedPrefabAssetInfo.prefabFileHash) { return(null); // cache is out of sync } return(cachedPrefabAssetInfo); }
// Returns true if overrides count changed during the update public bool MoveNext() { if (IsDone()) { return(false); } var assetRoot = m_PrefabAssetRoots[m_CurrentAssetIndex]; var startCount = m_OverridesCount[m_CurrentAssetIndex]; switch (m_CurrentStep) { case 0: { // First check if we have cached overides count for the prefab var path = AssetDatabase.GetAssetPath(assetRoot); var guid = AssetDatabase.AssetPathToGUID(path); var cachedPrefabAssetInfo = PrefabAssetStateCache.GetState(guid); if (cachedPrefabAssetInfo != null) { m_OverridesCount[m_CurrentAssetIndex] = cachedPrefabAssetInfo.overrideCount; m_ChangedCount = true; m_CurrentAssetIndex++; if (m_Debug) { Debug.Log($"[OverridesCounterForPrefabAssets] Using cached overridecount {cachedPrefabAssetInfo.overrideCount} ({path})"); } return(true); } } break; case 1: PropertyModification[] mods = PrefabUtility.GetPropertyModifications(assetRoot); foreach (PropertyModification mod in mods) { if (mod.target == null) { continue; } if (!PrefabUtility.IsDefaultOverride(mod)) { m_OverridesCount[m_CurrentAssetIndex]++; } } break; case 2: m_OverridesCount[m_CurrentAssetIndex] += PrefabOverridesUtility.GetAddedComponents(assetRoot).Count; break; case 3: m_OverridesCount[m_CurrentAssetIndex] += PrefabOverridesUtility.GetRemovedComponents(assetRoot).Count; break; case 4: m_OverridesCount[m_CurrentAssetIndex] += PrefabOverridesUtility.GetAddedGameObjects(assetRoot).Count; break; default: { // Cache result var path = AssetDatabase.GetAssetPath(assetRoot); var guid = AssetDatabase.AssetPathToGUID(path); var prefabAssetInfo = new PrefabAssetInfo(); prefabAssetInfo.overrideCount = m_OverridesCount[m_CurrentAssetIndex]; prefabAssetInfo.prefabFileHash = AssetDatabase.GetSourceAssetFileHash(guid); PrefabAssetStateCache.SetState(guid, prefabAssetInfo); if (m_Debug) { Debug.Log($"[OverridesCounterForPrefabAssets] Set cached overridecount {prefabAssetInfo.overrideCount} for {path}"); } // Move to next asset m_CurrentAssetIndex++; m_CurrentStep = 0; } break; } if (m_Debug) { Debug.Log($"[OverridesCounterForPrefabAssets] Current asset index: {m_CurrentAssetIndex}, current step: {m_CurrentStep}"); } m_CurrentStep++; // Simulate heavy calculation if (m_Debug) { System.Threading.Thread.Sleep(500); } m_ChangedCount = m_OverridesCount[m_CurrentAssetIndex] != startCount; return(true); }
// Internal for testing framework internal void SaveDirtyPrefabAssets(bool reloadInspectors) { if (assetTargets == null) { return; } if (assetTarget == null) { return; } m_DirtyPrefabAssets.Clear(); foreach (var asset in assetTargets) { // The asset could have been deleted when this method is called from OnDestroy(). // E.g delete the selected prefab asset from the Project Browser. if (asset == null) { continue; } if (!EditorUtility.IsPersistent(asset)) { continue; } if (!(asset is GameObject)) { continue; } var rootGameObject = (GameObject)asset; if (IsDirty(rootGameObject)) { string currentGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(rootGameObject)); var changeTracking = new TrackedAsset() { asset = rootGameObject, guid = currentGuid, hash = AssetDatabase.GetSourceAssetFileHash(currentGuid) }; m_DirtyPrefabAssets.Add(changeTracking); } } if (m_DirtyPrefabAssets.Count > 0) { AssetDatabase.StartAssetEditing(); try { foreach (var trackedAsset in m_DirtyPrefabAssets) { bool savedSuccesfully; PrefabUtility.SavePrefabAsset(trackedAsset.asset, out savedSuccesfully); if (!savedSuccesfully) { string title = L10n.Tr("Saving Failed"); string message = L10n.Tr("Check the Console window to get more insight into what needs to be fixed on the Prefab Asset.\n\nYou can open Prefab Mode to fix any issues on child GameObjects"); EditorUtility.DisplayDialog(title, message, L10n.Tr("OK")); m_SavingHasFailed = true; break; } } } finally { AssetDatabase.StopAssetEditing(); if (reloadInspectors) { foreach (var trackedAsset in m_DirtyPrefabAssets) { if (AssetDatabase.GetSourceAssetFileHash(trackedAsset.guid) != trackedAsset.hash) { // We only call ForceReloadInspectors (and not ForceRebuildInspectors) to ensure local inspector state // is not destroyed, such as a foldout state maintained by an editor (case 1255013). // And we need to reload Prefab asset inspectors in order for the preview to be regenerated since the preview shows // an instantiated Prefab. E.g disable a MeshRenderer on a Prefab Asset and the mesh should be hidden in the preview. EditorUtility.ForceReloadInspectors(); break; } } } } } }
// Internal for testing framework internal void SaveDirtyPrefabAssets(bool rebuildInspectors) { if (assetTargets == null) { return; } if (assetTarget == null) { return; } m_DirtyPrefabAssets.Clear(); foreach (var asset in assetTargets) { // The asset could have been deleted when this method is called from OnDestroy(). // E.g delete the selected prefab asset from the Project Browser. if (asset == null) { continue; } if (!EditorUtility.IsPersistent(asset)) { continue; } if (!(asset is GameObject)) { continue; } var rootGameObject = (GameObject)asset; if (IsDirty(rootGameObject)) { m_DirtyPrefabAssets.Add(rootGameObject); } } if (m_DirtyPrefabAssets.Count > 0) { bool sourceFileChangedAfterSaving = false; AssetDatabase.StartAssetEditing(); try { foreach (var rootGameObject in m_DirtyPrefabAssets) { var guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(rootGameObject)); var hashBeforeSaving = AssetDatabase.GetSourceAssetFileHash(guid); bool savedSuccesfully; PrefabUtility.SavePrefabAsset(rootGameObject, out savedSuccesfully); if (!savedSuccesfully) { string title = L10n.Tr("Saving Failed"); string message = L10n.Tr("Check the Console window to get more insight into what needs to be fixed on the Prefab Asset.\n\nYou can open Prefab Mode to fix any issues on child GameObjects"); EditorUtility.DisplayDialog(title, message, L10n.Tr("OK")); m_SavingHasFailed = true; break; } // Fix case 1239807: Prevent calling ForceRebuildInspectors() if the the user is dirtying the prefab asset on every CustomEditor::OnEnable() with a // value that is the same as before (so the artifact does not change). This fix avoids constant rebuilding of the Inspector window. sourceFileChangedAfterSaving |= AssetDatabase.GetSourceAssetFileHash(guid) != hashBeforeSaving; } } finally { AssetDatabase.StopAssetEditing(); // All inspectors needs to be rebuild to ensure property changes are reflected after saving the Prefab shown. // (Saving clears the m_DirtyIndex of the target which is used for updating inspectors via SerializedObject::UpdateIfRequiredOrScript() // and thus the cached dirty index in SerializedObject is not updated meaning the source object is not reloaded even though it changed) if (sourceFileChangedAfterSaving && rebuildInspectors) { EditorUtility.ForceRebuildInspectors(); } } } }