using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using System.Xml.Linq; using Wwise.Wooduan.Components; using Debug = UnityEngine.Debug; namespace Wwise.Wooduan.Tools { internal partial class AkWooduanComponentBackup : AkWooduanAssetSearcher { #region Fields // filter components that don't need to include internal readonly Dictionary ComponentsToSearch = new Dictionary(); // store one xml file per type of component private readonly Dictionary _outputTypes = new Dictionary(); internal bool SeparateXmlFiles = true; internal bool IncludePrefabsInScene = true; protected override string DefaultXmlPath { get { return AkWooduanScriptingTools.CombinePath(XmlDocDirectory, "AkWooduanComponents.xml"); } } private string IndividualXmlPath(Type type) { return AkWooduanScriptingTools.CombinePath(XmlDocDirectory, type.Name + ".xml"); } #endregion #region Init private static AkWooduanComponentBackup _instance; internal static AkWooduanComponentBackup Instance { get { if (!_instance) _instance = CreateInstance(); return _instance; } } // initialize delegates and xml roots private void RegisterComponent(ComponentImporter importer = null, ComponentExporter exporter = null) { var t = typeof(T); ComponentsToSearch[t] = true; _importers[t] = importer; _exporters[t] = exporter; } // get an xml file for a type of component private void LoadOrCreateXmlDoc(Type type) { var xmlPath = IndividualXmlPath(type); if (!File.Exists(xmlPath)) AkWooduanScriptingTools.WriteXml(xmlPath, new XElement("Root")); else { var xRoot = XDocument.Load(xmlPath).Root; _outputTypes[type] = xRoot; } } #endregion #region Export // one function per component to export data private delegate void ComponentExporter(AkComponent component, XElement node); private static readonly Dictionary _exporters = new Dictionary(); internal void Export() { var completed = false; var fileName = ""; CleanUp(); if (SeparateXmlFiles) { // clear xml files of all components foreach (var pair in ComponentsToSearch) { if (pair.Value) _outputTypes[pair.Key] = new XElement("Root"); } } else { // let user select a file to export to fileName = EditorUtility.SaveFilePanel("Export to", XmlDocDirectory, "AkWooduanComponents.xml", "xml"); if (string.IsNullOrEmpty(fileName)) return; } // export prefabs if (IncludeA) completed |= FindFiles(ParsePrefab, "Exporting Prefabs", "*.prefab"); // export scenes if (IncludeB) { // save the current scene var currentScene = SceneManager.GetActiveScene().path; completed |= FindFiles(ParseScene, "Exporting Scenes", "*.unity"); // reopen the scene saved EditorSceneManager.OpenScene(currentScene); } // if user did not cancel the search process, write xml file if (completed) { if (SeparateXmlFiles) { foreach (var pair in ComponentsToSearch) { if (pair.Value) AkWooduanScriptingTools.WriteXml(IndividualXmlPath(pair.Key), _outputTypes[pair.Key]); } } else AkWooduanScriptingTools.WriteXml(fileName, XRoot); EditorUtility.DisplayDialog("Process Finished!", string.Format("Found {0} components in {1} assets!", EditedCount, TotalCount), "OK"); } } // load a prefab and export all components in it internal void ParsePrefab(string assetPath) { var prefab = (GameObject)AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)); if (!prefab) return; if (SeparateXmlFiles) { var found = false; // iterate types first because xml files are separate foreach (var pair in ComponentsToSearch) { if (!pair.Value) continue; var xPrefab = new XElement("Prefab"); var components = prefab.GetComponentsInChildren(pair.Key, true); foreach (var component in components) { xPrefab.Add(ParseComponent((AkComponent)component)); } // component found, add prefab node to xml if (xPrefab.HasElements) { xPrefab.SetAttributeValue("AssetPath", assetPath); _outputTypes[pair.Key].Add(xPrefab); found = true; } } if (found) TotalCount++; } else { var xPrefab = new XElement("Prefab"); var components = prefab.GetComponentsInChildren(true); foreach (var component in components) { bool willSearch; if (ComponentsToSearch.TryGetValue(component.GetType(), out willSearch)) xPrefab.Add(ParseComponent(component)); } if (xPrefab.HasElements) { xPrefab.SetAttributeValue("AssetPath", assetPath); XRoot.Add(xPrefab); TotalCount++; } } } // load a scene and export all components in it internal void ParseScene(string assetPath) { var scene = EditorSceneManager.OpenScene(assetPath); if (!scene.IsValid()) return; if (SeparateXmlFiles) { var found = false; foreach (var pair in ComponentsToSearch) { var xScene = new XElement("Scene"); if (!pair.Value) continue; foreach (var rootGameObject in scene.GetRootGameObjects()) { var components = rootGameObject.GetComponentsInChildren(pair.Key, true); foreach (var component in components) { bool willSearch; if (ComponentsToSearch.TryGetValue(component.GetType(), out willSearch)) { // make sure component is saved just in scene if (ComponentBelongsToScene(component)) xScene.Add(ParseComponent((AkComponent) component)); } } } if (xScene.HasElements) { xScene.SetAttributeValue("AssetPath", assetPath); _outputTypes[pair.Key].Add(xScene); found = true; } } if (found) TotalCount++; } else { var xScene = new XElement("Scene"); foreach (var rootGameObject in scene.GetRootGameObjects()) { var components = rootGameObject.GetComponentsInChildren(true); foreach (var component in components) { bool willSearch; if (ComponentsToSearch.TryGetValue(component.GetType(), out willSearch)) { if (ComponentBelongsToScene(component)) xScene.Add(ParseComponent(component)); } } } if (xScene.HasElements) { xScene.SetAttributeValue("AssetPath", assetPath); XRoot.Add(xScene); TotalCount++; } } } // check if a component is prefab variant or just in scene private bool ComponentBelongsToScene(Component component) { #if UNITY_2018_3_OR_NEWER // find the root game object node of prefab var prefab = PrefabUtility.GetNearestPrefabInstanceRoot(component.gameObject); // game object is not a prefab at all if (prefab) { // user does not want to include it if (!IncludePrefabsInScene) return false; // check if any override matches this component var overrides = PrefabUtility.GetObjectOverrides(prefab, true); foreach (var objectOverride in overrides) { var c = objectOverride.instanceObject as AkComponent; if (c == component) return true; } // can't find any overrides return false; } #else // find a prefab, see if user wants to include it if (PrefabUtility.GetPrefabType(component.gameObject) != PrefabType.None) return IncludePrefabsInScene; #endif // not a prefab, must be in scene only return true; } // write component node private XElement ParseComponent(AkComponent component) { var type = component.GetType(); var xComponent = new XElement("Component"); xComponent.SetAttributeValue("Type", type.Name); xComponent.SetAttributeValue("GameObject", GetGameObjectPath(component.transform)); // export component data _exporters[type](component, xComponent); EditedCount++; return xComponent; } #endregion #region Import // one function per component to import data private delegate bool ComponentImporter(AkComponent component, XElement node); private static readonly Dictionary _importers = new Dictionary(); internal void Import() { CleanUp(); AsCompareWindow.MissingComponents.Clear(); AsCompareWindow.ModifiedComponents.Clear(); // select an xml file to import from ImportedXmlPath = EditorUtility.OpenFilePanel("Import from", XmlDocDirectory, "xml"); if (ImportedXmlPath == null) return; ReadXmlData(ImportedXmlPath); if (IncludeA) ImportOrComparePrefabs(false); if (IncludeB) ImportOrCompareScenes(false); EditorUtility.DisplayProgressBar("Saving", "Overwriting assets...(might take a few minutes)", 1f); AssetDatabase.SaveAssets(); EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("Process Finished!", string.Format("Updated {0} components out of {1}!", EditedCount, TotalCount), "OK"); } private void ImportOrComparePrefabs(bool isCompare) { var xPrefabs = XRoot.Elements("Prefab").ToList(); var searchPath = AkWooduanScriptingTools.ShortPath(SearchPath); try { for (var i = 0; i < xPrefabs.Count; i++) { var assetPath = AkWooduanScriptingTools.GetXmlAttribute(xPrefabs[i], "AssetPath"); if (!assetPath.Contains(searchPath)) continue; if (isCompare) ComparePrefab(xPrefabs[i]); else ImportPrefab(xPrefabs[i]); if (EditorUtility.DisplayCancelableProgressBar("Processing prefabs", assetPath, (i + 1f) / TotalCount)) break; } } catch (Exception e) { Debug.LogException(e); EditorUtility.ClearProgressBar(); } } internal bool ImportPrefab(XElement xPrefab) { var prefabPath = AkWooduanScriptingTools.GetXmlAttribute(xPrefab, "AssetPath"); var prefab = AssetDatabase.LoadAssetAtPath(prefabPath); if (!prefab) { Debug.LogError("Backup Failed: Can't find prefab at " + prefabPath); return false; } var modified = false; foreach (var xComponent in xPrefab.Elements()) { TotalCount++; // locate the game object in prefab var gameObjectPath = AkWooduanScriptingTools.GetXmlAttribute(xComponent, "GameObject"); var gameObject = GetGameObject(prefab, gameObjectPath); if (gameObject == null) { Debug.LogError("Backup Failed: Can't find game object at " + gameObjectPath + " in prefab " + prefabPath); continue; } var type = AkWooduanScriptingTools.StringToType(AkWooduanScriptingTools.GetXmlAttribute(xComponent, "Type")); var component = gameObject.GetComponent(type) as AkComponent; // create new component if not found if (!component) component = gameObject.AddComponent(type) as AkComponent; if (ComponentModified(component, xComponent)) { EditedCount++; modified = true; SaveComponentAsset(prefab, prefabPath); } } return modified; } private void ImportOrCompareScenes(bool isCompare) { var currentScene = SceneManager.GetActiveScene().path; var xScenes = XRoot.Elements("Scene").ToList(); var searchPath = AkWooduanScriptingTools.ShortPath(SearchPath); try { for (var i = 0; i < xScenes.Count; i++) { var assetPath = AkWooduanScriptingTools.GetXmlAttribute(xScenes[i], "AssetPath"); if (!assetPath.Contains(searchPath)) continue; if (isCompare) CompareScene(xScenes[i]); else ImportScene(xScenes[i]); if (EditorUtility.DisplayCancelableProgressBar("Processing scenes", assetPath, (i + 1f) / TotalCount)) break; } } catch (Exception e) { Debug.LogException(e); EditorUtility.ClearProgressBar(); } EditorSceneManager.OpenScene(currentScene); } internal bool ImportScene(XElement xScene) { TotalCount++; var scenePath = AkWooduanScriptingTools.GetXmlAttribute(xScene, "AssetPath"); var scene = EditorSceneManager.OpenScene(scenePath); if (!scene.IsValid()) { Debug.LogError("Backup Failed: Can't find scene at " + scenePath); return false; } var modified = false; foreach (var xComponent in xScene.Elements()) { var gameObjectPath = AkWooduanScriptingTools.GetXmlAttribute(xComponent, "GameObject"); foreach (var rootGameObject in scene.GetRootGameObjects()) { var gameObject = GetGameObject(rootGameObject, gameObjectPath); if (!gameObject) { Debug.LogError("Backup Failed: Can't find game object at " + gameObjectPath + " in scene " + scenePath); continue; } var type = AkWooduanScriptingTools.StringToType(AkWooduanScriptingTools.GetXmlAttribute(xComponent, "Type")); var component = gameObject.GetComponent(type) as AkComponent; if (!component) component = gameObject.AddComponent(type) as AkComponent; if (ComponentModified(component, xComponent)) { EditedCount++; modified = true; EditorUtility.SetDirty(component); } break; } } if (modified) EditorSceneManager.SaveScene(scene); EditorSceneManager.CloseScene(scene, false); return modified; } internal static void SaveComponentAsset(GameObject go, string assetPath) { // if game object is from a prefab, save the prefab if (assetPath.EndsWith(".prefab")) { #if UNITY_2018_3_OR_NEWER var stage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); if (stage == null) PrefabUtility.SavePrefabAsset(go); else EditorUtility.SetDirty(go); #else #if UNITY_2018_1_OR_NEWER var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go); #else var prefab = PrefabUtility.GetPrefabParent(go); #endif var prefabRoot = PrefabUtility.FindPrefabRoot(go); PrefabUtility.ReplacePrefab(prefabRoot, prefab, ReplacePrefabOptions.ConnectToPrefab); #endif } // game object belongs to scene, save the scene else EditorSceneManager.SaveScene(SceneManager.GetActiveScene()); } #endregion #region Compare internal void Compare() { CleanUp(); ImportedXmlPath = EditorUtility.OpenFilePanel("Import from", XmlDocDirectory, "xml"); if (string.IsNullOrEmpty(ImportedXmlPath)) return; ReadXmlData(ImportedXmlPath); if (IncludeA) ImportOrComparePrefabs(true); if (IncludeB) ImportOrCompareScenes(true); AkComponentCompare.ShowWindow(); EditorUtility.ClearProgressBar(); } private void CompareScene(XElement xScene) { var scenePath = AkWooduanScriptingTools.GetXmlAttribute(xScene, "AssetPath"); var scene = EditorSceneManager.OpenScene(scenePath); if (!scene.IsValid()) { Debug.LogError("Backup Failed: Can't find scene at " + scenePath); return; } foreach (var xComponent in xScene.Elements()) { var gameObjectPath = AkWooduanScriptingTools.GetXmlAttribute(xComponent, "GameObject"); var type = AkWooduanScriptingTools.StringToType(AkWooduanScriptingTools.GetXmlAttribute(xComponent, "Type")); foreach (var rootGameObject in scene.GetRootGameObjects()) { var gameObject = GetGameObject(rootGameObject, gameObjectPath); if (!gameObject) { Debug.LogError("Backup Failed: Can't find game object at " + gameObjectPath + " in scene " + scenePath); continue; } var data = new ComponentComparisonData { AssetPath = scenePath, ComponentData = xComponent, BackupStatus = ComponentBackupStatus.Unhandled }; var component = gameObject.GetComponent(type) as AkComponent; // can not find component, it is missing if (!component) AsCompareWindow.MissingComponents.Add(data); // can find component but without any data else if (!component.IsValid()) AsCompareWindow.EmptyComponents.Add(data); else { // create temp component to make sure it doesn't overwrite original component var tempGo = Instantiate(component); // component is modified if (ComponentModified(tempGo, xComponent)) AsCompareWindow.ModifiedComponents.Add(data); DestroyImmediate(tempGo.gameObject, true); } // go to next component break; } } EditorSceneManager.CloseScene(scene, false); } private void ComparePrefab(XElement xPrefab) { var prefabPath = AkWooduanScriptingTools.GetXmlAttribute(xPrefab, "AssetPath"); var prefab = AssetDatabase.LoadAssetAtPath(prefabPath); if (!prefab) { Debug.LogError("Backup Failed: Can't find prefab at " + prefabPath); return; } foreach (var xComponent in xPrefab.Elements()) { var gameObjectPath = AkWooduanScriptingTools.GetXmlAttribute(xComponent, "GameObject"); var gameObject = GetGameObject(prefab, gameObjectPath); if (!gameObject) { Debug.LogError("Backup Failed: Can't find game object at " + gameObjectPath + " in prefab " + prefabPath); continue; } var type = AkWooduanScriptingTools.StringToType(AkWooduanScriptingTools.GetXmlAttribute(xComponent, "Type")); var data = new ComponentComparisonData { AssetPath = prefabPath, ComponentData = xComponent, BackupStatus = ComponentBackupStatus.Unhandled }; var component = gameObject.GetComponent(type) as AkComponent; if (!component) component = gameObject.AddComponent(type) as AkComponent; if (!component) AsCompareWindow.MissingComponents.Add(data); else if (!component.IsValid()) AsCompareWindow.EmptyComponents.Add(data); else { var tempGo = Instantiate(component); if (ComponentModified(tempGo, xComponent)) AsCompareWindow.ModifiedComponents.Add(data); DestroyImmediate(tempGo.gameObject, true); } } } private static bool ComponentModified(AkComponent component, XElement node) { var type = component.GetType(); return _importers[type] != null && _importers[type](component, node); } #endregion #region Locate internal static string FindComponentAssetPath(Component component, bool defaultOnPrefab = false) { var path = AssetDatabase.GetAssetPath(component); // path won't be empty if editing on top level of a prefab if (string.IsNullOrEmpty(path)) { #if UNITY_2018_3_OR_NEWER //2018.3 and later moves prefab editing to a separate stage var stage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); path = stage != null ? stage.prefabAssetPath : SceneManager.GetActiveScene().path; #else // if the component is from part of a prefab if (PrefabUtility.GetPrefabType(component.gameObject) != PrefabType.None) { #if UNITY_2018_1_OR_NEWER var prefab = PrefabUtility.GetCorrespondingObjectFromSource(component.gameObject); #else var prefab = PrefabUtility.GetPrefabParent(component.gameObject); #endif // ask if user wants to save it on prefab or scene if (defaultOnPrefab || EditorUtility.DisplayDialog("Options", "Do you want to apply to prefab or its scene variant?", "Prefab", "Scene")) path = AssetDatabase.GetAssetPath(prefab); else path = SceneManager.GetActiveScene().path; } else path = SceneManager.GetActiveScene().path; #endif } return path; } private XElement FindAssetNode(string assetPath, Type type, bool createIfMissing) { LoadOrCreateXmlDoc(type); var xAsset = _outputTypes[type].Elements().FirstOrDefault(x => assetPath == AkWooduanScriptingTools.GetXmlAttribute(x, "AssetPath")); // create a new asset node if (xAsset == null && createIfMissing) { xAsset = new XElement(assetPath.EndsWith(".prefab") ? "Prefab" : "Scene"); xAsset.SetAttributeValue("AssetPath", assetPath); _outputTypes[type].Add(xAsset); } return xAsset; } private static XElement FindComponentNode(XElement xAsset, Component component) { return xAsset.Elements().FirstOrDefault(x => GetGameObjectPath(component.transform) == AkWooduanScriptingTools.GetXmlAttribute(x, "GameObject")); } internal bool ComponentBackedUp(string assetPath, AkComponent component) { var xAsset = FindAssetNode(assetPath, component.GetType(), false); if (xAsset == null) return false; return FindComponentNode(xAsset, component) != null; } #endregion #region Update internal bool UpdateXmlFromComponent(string assetPath, AkComponent component) { var type = component.GetType(); // locate the component node from xml var xAsset = FindAssetNode(assetPath, type, true); var xComponent = FindComponentNode(xAsset, component); var xTemp = ParseComponent(component); // can't find existing node, create a new one if (xComponent == null) xAsset.Add(xTemp); else { // compare temp node with existing node if (XNode.DeepEquals(xTemp, xComponent)) return false; xComponent.ReplaceWith(xTemp); } // overwrite xml file after update AkWooduanScriptingTools.WriteXml(IndividualXmlPath(type), _outputTypes[type]); return true; } #endregion #region Revert internal bool RevertComponentToXml(string assetPath, AkComponent component) { var xAsset = FindAssetNode(assetPath, component.GetType(), true); var xComponent = FindComponentNode(xAsset, component); // if component not found, create a new one if (xComponent == null) return UpdateXmlFromComponent(assetPath, component); // revert component data to its xml return ComponentModified(component, xComponent); } #endregion #region Remove // remove all components in a folder internal void RemoveAll() { // reset counters CleanUp(); if (IncludeA) FindFiles(RemoveAllInPrefab, "Removing Prefabs", "*.prefab"); if (IncludeB) { var currentScene = SceneManager.GetActiveScene().path; FindFiles(RemoveAllInScene, "Removing Scenes", "*.unity"); EditorSceneManager.OpenScene(currentScene); } EditorUtility.DisplayDialog("Process Finished!", string.Format("Removed {0} components!", TotalCount), "OK"); } // remove unsaved components in a folder internal void RemoveUnsaved() { CleanUp(); if (IncludeA) FindFiles(RemoveUnsavedInPrefab, "Removing Prefabs not Backed up", "*.prefab"); if (IncludeB) { var currentScene = SceneManager.GetActiveScene().path; FindFiles(RemoveUnsavedInScene, "Removing Scenes not Backed up", "*.unity"); EditorSceneManager.OpenScene(currentScene); } EditorUtility.DisplayDialog("Process Finished!", string.Format("Removed {0} components!", TotalCount), "OK"); } internal void RemoveUnsavedInScene(string assetPath) { var scene = EditorSceneManager.OpenScene(assetPath); if (!scene.IsValid()) return; foreach (var rootGameObject in scene.GetRootGameObjects()) { RemoveComponent(assetPath, rootGameObject, false); } EditorSceneManager.SaveScene(scene); } internal void RemoveUnsavedInPrefab(string assetPath) { var prefab = AssetDatabase.LoadAssetAtPath(assetPath); if (!prefab) return; RemoveComponent(assetPath, prefab, false); SaveComponentAsset(prefab, assetPath); } private void RemoveComponent(string assetPath, GameObject gameObject, bool removeAll) { var components = gameObject.GetComponentsInChildren(true); foreach (var component in components) { // filter out types that should be kept bool willSearch; if (ComponentsToSearch.TryGetValue(component.GetType(), out willSearch)) { if (removeAll || !ComponentBackedUp(assetPath, component)) { TotalCount++; DestroyImmediate(component, true); } } } } internal void RemoveAllInScene(string assetPath) { var scene = EditorSceneManager.OpenScene(assetPath); if (!scene.IsValid()) return; var xAsset = XRoot.Elements("Scene").FirstOrDefault(x => assetPath == AkWooduanScriptingTools.GetXmlAttribute(x, "AssetPath")); if (xAsset != null) xAsset.Remove(); foreach (var rootGameObject in scene.GetRootGameObjects()) { RemoveComponent(assetPath, rootGameObject, true); } EditorSceneManager.SaveScene(scene); } internal void RemoveAllInPrefab(string assetPath) { var prefab = AssetDatabase.LoadAssetAtPath(assetPath); if (!prefab) return; var xAsset = XRoot.Elements("Prefab").FirstOrDefault(x => assetPath == AkWooduanScriptingTools.GetXmlAttribute(x, "AssetPath")); if (xAsset != null) xAsset.Remove(); RemoveComponent(assetPath, prefab, true); SaveComponentAsset(prefab, assetPath); } // remove node from component inspector internal void RemoveComponentXml(string assetPath, AkComponent component) { var type = component.GetType(); var xAsset = FindAssetNode(assetPath, type, false); if (xAsset == null) return; var xComponent = FindComponentNode(xAsset, component); if (xComponent == null) return; AkWooduanScriptingTools.RemoveComponentXml(xComponent); AkWooduanScriptingTools.WriteXml(IndividualXmlPath(type), _outputTypes[type]); } // remove node from compare window private void RemoveComponentXml(ComponentComparisonData data) { var type = AkWooduanScriptingTools.StringToType(AkWooduanScriptingTools.GetXmlAttribute(data.ComponentData, "Type")); var xAsset = FindAssetNode(data.AssetPath, type, false); if (xAsset == null) return; var xComponent = xAsset.Elements().FirstOrDefault(x => XNode.DeepEquals(x, data.ComponentData)); if (xComponent == null) return; AkWooduanScriptingTools.RemoveComponentXml(xComponent); AkWooduanScriptingTools.WriteXml(ImportedXmlPath, XRoot); } #endregion #region Combine // combine all individual xml files into a large one internal void Combine() { ReadXmlData(); XRoot.RemoveAll(); foreach (var type in ComponentsToSearch.Keys) { LoadOrCreateXmlDoc(type); } foreach (var xType in _outputTypes.Values) { foreach (var xAsset in xType.Elements()) { var assetPath = AkWooduanScriptingTools.GetXmlAttribute(xAsset, "AssetPath"); var xFullAsset = XRoot.Elements().FirstOrDefault(x => assetPath == AkWooduanScriptingTools.GetXmlAttribute(x, "AssetPath")); if (xFullAsset == null) { xFullAsset = assetPath.EndsWith(".prefab") ? new XElement("Prefab") : new XElement("Scene"); xFullAsset.SetAttributeValue("AssetPath", assetPath); XRoot.Add(xFullAsset); } foreach (var xComponent in xAsset.Elements()) { xFullAsset.Add(xComponent); TotalCount++; } } } AkWooduanScriptingTools.WriteXml(DefaultXmlPath, XRoot); EditorUtility.DisplayDialog("Success", string.Format("Combined {0} components in prefabs and scenes!", TotalCount), "OK"); } #endregion private class AkComponentCompare : AsCompareWindow { internal static void ShowWindow() { var window = (AkComponentCompare) GetWindow(typeof(AkComponentCompare)); window.position = new Rect(500, 300, 700, 500); window.titleContent = new GUIContent("Compare Components"); } protected override void DisplayData(ComponentComparisonData data) { var type = AkWooduanScriptingTools.GetXmlAttribute(data.ComponentData, "Type"); if (GUILayout.Button(string.Format("{0}: {1} ({2})", type, data.AssetName, data.BackupStatus), GUI.skin.label)) AsXmlInfo.Init(data.ComponentData); } // auto select the component asset protected override void LocateComponent(ComponentComparisonData data) { var gameObjectPath = AkWooduanScriptingTools.GetXmlAttribute(data.ComponentData, "GameObject"); if (data.AssetPath.EndsWith(".prefab")) { var prefab = AssetDatabase.LoadAssetAtPath(data.AssetPath); if (prefab) FindGameObjectAndSelect(prefab, gameObjectPath); } else { EditorSceneManager.OpenScene(data.AssetPath); var scene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = scene.GetRootGameObjects(); foreach (var rootGameObject in rootGameObjects) { FindGameObjectAndSelect(rootGameObject, gameObjectPath); } } } protected override void RemoveComponent(ComponentComparisonData data) { Instance.RemoveComponentXml(data); } private static void FindGameObjectAndSelect(GameObject gameObject, string gameObjectPath) { var child = GetGameObject(gameObject, gameObjectPath); if (child) Selection.activeObject = child; } } } }