public virtual bool SearchNextAsset() { if (index >= assetPaths.Count) { return(false); } string assetPath = assetPaths[index]; index++; bool hasMoreItems = index != assetPaths.Count; SearchAssetData assetData = job.searchAssetsData[assetPath]; if (assetData.hasBeenSearched) { //looks like the item has already been searched! return(hasMoreItems); } assetData.hasBeenSearched = true; job.assetData = assetData; if (job.searchItemCaresAboutAsset()) { // Debug.Log("[SearchSubJob] processing:"+assetPath); processAsset(assetPath); } else { // Debug.Log("[SearchSubJob] ignoring:"+assetPath); } return(hasMoreItems); }
public static bool IsPrefabObjectReplaceable(GameObject gameObject, SearchAssetData assetData, out string reason) { reason = ""; #if UNITY_2018_3_OR_NEWER if (!assetData.CanReplaceObject(gameObject, out reason)) { return(false); } if (PrefabUtility.GetPrefabInstanceStatus(gameObject) == PrefabInstanceStatus.NotAPrefab) { return(true); } if (PrefabUtility.IsOutermostPrefabInstanceRoot(gameObject)) { return(true); } else { reason = "Cannot replace internal prefab objects."; return(false); } #else return(true); #endif }
public static PathInfo InitWithScriptableObject(ScriptableObject so, SearchAssetData assetData) { PathInfo pi = GetPathInfo(so, assetData); pi.objectPath = ""; return(pi); }
void addIgnorableResource(string path) { SearchAssetData data = new SearchAssetData(path); data.hasBeenSearched = true; searchAssetsData[path] = data; }
public void searchDependencies(UnityEngine.Object[] rootObjects) { if (!scope.searchDependencies) { return; } if (scope.assetScope == SearchScope.allAssets && scope.projectScope == ProjectScope.EntireProject) { // We are searching literally everything we can, so no need to load // things more. return; } //search dependencies UnityEngine.Object[] dependencies = EditorUtility.CollectDependencies(rootObjects.ToArray()); foreach (UnityEngine.Object dependency in dependencies) { string path = AssetDatabase.GetAssetPath(dependency); if (!searchAssetsData.ContainsKey(path)) { // empty strings mean it is local object. if (path != string.Empty) { // do we support this file extension? if (isSearchable(path)) { SearchAssetData data = new SearchAssetData(path); searchAssetsData.Add(path, data); searchDependency(data); } } } } }
public void addDependency(SearchAssetData dependency) { if (dependencies == null) { dependencies = new List <SearchAssetData>(); } dependencies.Add(dependency); }
static void AddAsset(string assetPath, List <SearchAssetData> assets) { SearchAssetData assetData = AssetForPath(assetPath); if (assetData != null) { assets.Add(assetData); } }
public void AddAsset(SearchAssetData assetData) { searchAssetsData.Add(assetData.assetPath, assetData); if (assetData is SceneSearchAssetData) { searchIncludesScenes = true; } if (assetData.containsScripts) { searchIncludesScripts = true; } searchAssets.Add(assetData); }
protected static string ToPath(UnityEngine.Object o, SearchAssetData assetData) { if (o is Component) { Component c = (Component)o; return(ToPath(c.gameObject, assetData) + "." + c.GetType().Name); } if (o is GameObject) { GameObject go = (GameObject)o; return(ToPath(go, assetData)); } return(""); }
static void replaceInstances(SearchJob parentJob, SearchItem item, GameObject oldValue, GameObject newValue) { SearchItemSet searchSet = new SearchItemSet(); searchSet.OnDeserialization(); searchSet.AddNew(Keys.Global, false); SearchItemGlobal searchItem = (SearchItemGlobal)searchSet.items[0]; searchItem.SetType("Object"); DynamicTypeObject dto = (DynamicTypeObject)searchItem.GetDTDFor(typeof(UnityEngine.Object)); dto.SearchSubObjects = true; dto.SetObject(oldValue); ReplaceItemObject replaceItem = (ReplaceItemObject)dto.ReplaceItem; replaceItem.SetObject(newValue); SearchOptions options = new SearchOptions(); options.searchType = SearchType.SearchAndReplace; // does this matter anymore since asset scope is now essentially defined by what assets are passed in? SearchScopeData searchScope = new SearchScopeData(ProjectScope.SpecificLocation, AssetScope.Prefabs, new ObjectID(AssetDatabase.LoadAssetAtPath <UnityEngine.Object>(parentJob.assetData.assetPath)), false, parentJob.scope.loadPrefab); SearchJob subJob = new SearchJob(searchSet, options, searchScope); SearchAssetData assetData = parentJob.assetData.Clone(); subJob.AddAsset(assetData); subJob.Execute(); // Now that we've executed the job we have to save a list of all objects from search results, because as soon as // we swap out the new object, the old object's position may shift in the hierarchy, making the PathInfo stale. SearchResultGroup group = subJob.resultSet.results[searchItem.sortIndex]; List <UnityEngine.Object> resultObjects = new List <Object>(); foreach (SearchResult result in group.results) { UnityEngine.Object resultObj = EditorUtility.InstanceIDToObject(result.pathInfo.objectID); resultObjects.Add(resultObj); } UnityEngine.Object.DestroyImmediate(oldValue); // now that we've deleted the object, let's rebuild the objects. for (int i = 0; i < resultObjects.Count; i++) { SearchResult result = group.results[i]; result.pathInfo = PathInfo.GetPathInfo(resultObjects[i], assetData); } parentJob.AddResultsFromSubsearch(item, subJob.resultSet.results[searchItem.sortIndex]); }
//Verifies our addition to the list and maintains that no duplicates can occur. protected void addItems(IEnumerable <string> addedPaths) { foreach (string addedPath in addedPaths) { if (!job.searchAssetsData.ContainsKey(addedPath)) { // Debug.Log("[SearchSubJob] Adding:"+addedPath); SearchAssetData data = new SearchAssetData(addedPath); data.assetRequiresImporter = assetRequiresImporter; data.assetScope = assetScope; job.searchAssetsData.Add(addedPath, data); assetPaths.Add(addedPath); } } }
protected static string ToPath(GameObject go, SearchAssetData assetData) { string retVal = ""; Transform t = go.transform; while (t != null) { retVal = t.gameObject.name + retVal; t = t.parent; if (t != null) { retVal = "::" + retVal; } } return("/" + retVal + assetData.internalAssetPath); }
public static PathInfo GetPathInfo(GameObject go, SearchAssetData assetData) { PathInfo pi = new PathInfo(); pi.objectID = go.GetInstanceID(); pi.objID = new ObjectID(go); pi.objID.obj = null; pi.gameObjectID = pi.objectID; pi.assetPath = assetData.assetPath; pi.prefabType = PrefabUtil.GetPrefabType(go); pi.objectPath = ToPath(go, assetData); pi.compactObjectPath = go.name; return(pi); }
private IEnumerator searchDependencies(UnityEngine.Object[] rootObjects) { if (rootObjects == null || rootObjects.Length == 0) { yield break; } if (!scope.searchDependencies) { yield break; } if (scope.assetScope == SearchScope.allAssets && scope.projectScope == ProjectScope.EntireProject) { // We are searching literally everything we can, so no need to load // things more. yield break; } //search dependencies UnityEngine.Object[] dependencies = EditorUtility.CollectDependencies(rootObjects); foreach (UnityEngine.Object dependency in dependencies) { string path = AssetDatabase.GetAssetPath(dependency); if (!searchAssetsData.ContainsKey(path)) { // empty strings mean it is local object. if (path != string.Empty) { // do we support this file extension? if (isSearchable(path)) { SearchAssetData dependencyAsset = SearchAssetFactory.AssetForPath(path); if (dependencyAsset != null) { searchAssetsData[path] = dependencyAsset; dependencyAssets.Add(dependencyAsset); searchAsset(dependencyAsset); dependencyAsset.Unload(); yield return(null); } } } } } }
/** * Provides functionality to create path information to an object: Folders->Objects->Monobehaviour->Property */ public static PathInfo GetPathInfo(SerializedProperty prop, SearchAssetData assetData) { UnityEngine.Object obj = prop.serializedObject.targetObject; PathInfo pi = null; if (obj is Component) { Component c = (Component)obj; pi = InitWithComponent(c, c.gameObject, assetData); if (c is MonoBehaviour) { //Get the class information and attach it, then the property path MonoBehaviour m = (MonoBehaviour)c; MonoScript ms = MonoScript.FromMonoBehaviour(m); pi.objectPath = ToPath(m.gameObject, assetData) + "->" + ms.GetClass().ToString() + "." + prop.propertyPath; } else { // Just a component! GetType will do. pi.objectPath = ToPath(c.gameObject, assetData) + "->" + c.GetType().ToString() + "." + prop.propertyPath; } pi.compactObjectPath = c.gameObject.name + " (" + c.GetType().Name + ")." + prop.propertyPath; } else if (obj is GameObject) { pi = GetPathInfo((GameObject)obj, assetData); pi.objectPath += "." + prop.propertyPath; } else if (obj is Material) { pi = GetPathInfo(obj, assetData); pi.objectPath = demanglePropertyPathForMaterial(prop); pi.compactObjectPath = obj.name + demanglePropertyPathForMaterial(prop); } else if (obj is UnityEngine.Object) { pi = GetPathInfo(obj, assetData); pi.objectPath = assetData.internalAssetPath + "." + prop.propertyPath; } else { Debug.Log("[PathInfo] Cannot guess object type:" + obj); } return(pi); }
public void searchDependency(SearchAssetData data) { asset = (UnityEngine.Object)AssetDatabase.LoadAssetAtPath(data.assetPath, typeof(UnityEngine.Object)); assetData = data; if (asset is GameObject) { GameObject go = (GameObject)asset; searchGameObject(go); } else { searchObject(asset); } if (assetData.assetIsDirty) { //TODO save asset? } assetData.hasBeenSearched = true; }
private void searchAsset(SearchAssetData searchAsset) { if (searchAsset == null) { return; } try{ //todo: optimize and re-write caresAboutAsset(). if (!searchAsset.hasBeenSearched) { assetData = searchAsset; searchAsset.ProcessAsset(this); searchAsset.hasBeenSearched = true; } }catch (System.Exception ex) { Debug.LogException(ex); resultSet.status = SearchStatus.InProgress; resultSet.statusMsg = "An exception occurred: " + ex.ToString(); } }
public static PathInfo GetPathInfo(UnityEngine.Object obj, SearchAssetData assetData) { PathInfo pi = new PathInfo(); pi.objectID = obj.GetInstanceID(); pi.objID = new ObjectID(obj); pi.objID.obj = null; pi.gameObjectID = pi.objectID; pi.assetPath = assetData.assetPath; pi.prefabType = PrefabTypes.NotAPrefab; if (obj.name == string.Empty) { pi.objectPath = obj.GetType().ToString(); pi.compactObjectPath = pi.objectPath; } else { pi.objectPath = obj.name; pi.compactObjectPath = pi.objectPath; } return(pi); }
// Currently used by DynamicTypeClass when matching classes, and also internally. // parent is passed in because its possible component can be null! public static PathInfo InitWithComponent(Component c, GameObject parent, SearchAssetData assetData) { PathInfo pi = new PathInfo(); if (c != null) { pi.objID = new ObjectID(c); pi.objectID = c.GetInstanceID(); } else { pi.objID = new ObjectID(parent); } pi.objID.obj = null; pi.gameObjectID = parent.GetInstanceID(); pi.prefabType = PrefabUtil.GetPrefabType(parent); pi.assetPath = assetData.assetPath; pi.objectPath = ToPath(parent, assetData); pi.compactObjectPath = parent.name; return(pi); }
public void SearchProperty(SearchJob job, SearchItem item, SerializedProperty prop) { bool onlyVisible = !AnimationUtil.isAnimationObject(prop.serializedObject.targetObject); bool isScene = job.assetData.assetScope == AssetScope.Scenes; SerializedProperty iterator = prop.Copy(); SerializedProperty endProperty = null; if (depth == 0) { } else { endProperty = iterator.GetEndProperty(); } // if(endProperty != null) // { // Debug.Log("[SearchItemGlobal] STARTING on "+iterator.propertyPath + " ENDING on "+endProperty.propertyPath); // } while (Next(iterator, onlyVisible)) { if (ignorePropertyOfType(iterator)) { continue; } if (endProperty != null && SerializedProperty.EqualContents(iterator, endProperty)) { return; } // Its possible that we may have sub-objects that are serialized // scriptable objects within a scene. These aren't scriptable objects // on disk, and so we need to create a SerializedObject representation // and go a bit deeper. if (isScene) { if (iterator.propertyType == SerializedPropertyType.ObjectReference && iterator.objectReferenceValue is ScriptableObject) { string path = AssetDatabase.GetAssetPath(iterator.objectReferenceValue.GetInstanceID()); if (path == "") { // Debug.Log("[SearchItemGlobal] found scriptable object serialized within a scene."+iterator.propertyPath); SerializedObject so = new SerializedObject(iterator.objectReferenceValue); recursiveDepth++; if (recursiveDepth < 100) { string internalID = job.assetData.assetPath + so.targetObject.GetInstanceID(); SearchAssetData internalObjectData = null; if (!job.searchAssetsData.TryGetValue(internalID, out internalObjectData)) { // Debug.Log("Searching:"+ iterator.propertyPath + " " +so.targetObject.GetInstanceID()); job.addInternalAsset(job.assetData.assetPath, so.targetObject.GetInstanceID()); SearchProperty(job, item, so.GetIterator()); } // else{ // Debug.Log("Already searched this internal object:"+so.targetObject.GetInstanceID()); // } } else { // hit recursive depth! Debug.Log("[Search & Replace] Recursive depth hit!"); } recursiveDepth--; } } } searchPropertyInternal(job, item, prop, iterator); } if (typeHidesName(prop.serializedObject.targetObject)) { SerializedProperty nameProp = prop.serializedObject.FindProperty("m_Name"); searchPropertyInternal(job, item, prop, nameProp); } }
public void Execute() { addIgnorableResources(); string[] assetPaths = AssetDatabase.GetAllAssetPaths(); AnimationMode.StopAnimationMode(); // If recording is on, it will hose the animation. subjobs.Add(new SearchSubJob(this, AssetScope.Prefabs, assetPaths, new string[] { ".prefab" }, false)); //scenes are oh so 'special'. sceneSubJob = new SceneSubJob(this, AssetScope.Scenes, assetPaths, new string[] { ".unity" }); subjobs.Add(sceneSubJob); subjobs.Add(new SearchSubJob(this, AssetScope.Materials, assetPaths, new string[] { ".mat" }, false)); subjobs.Add(new SearchSubJob(this, AssetScope.ScriptableObjects, assetPaths, new string[] { ".asset" }, false)); subjobs.Add(new SearchSubJob(this, AssetScope.Animations, assetPaths, new string[] { ".anim" }, false)); subjobs.Add(new SearchSubJob(this, AssetScope.Animators, assetPaths, new string[] { ".controller" }, false)); subjobs.Add(new SearchSubJob(this, AssetScope.AudioClips, assetPaths, new string[] { ".wav", ".mp3" }, true)); subjobs.Add(new SearchSubJob(this, AssetScope.Textures, assetPaths, new string[] { ".png", ".psd", ".tiff", ".tif", ".tga", ".gif", ".bmp", ".jpg", ".jpeg", ".iff", ".pict" }, true)); subjobs.Add(new SceneObjectSubJob(this, AssetScope.None, assetPaths, new string[] { "" })); foreach (SearchSubJob subjob in subjobs) { totalItems += subjob.assetPaths.Count; } search.OnSearchBegin(); result = new SearchResultSet(search); result.status = SearchStatus.InProgress; currentItem = 1; if (sceneSubJob.assetPaths.Count > 0 && scope.projectScope != ProjectScope.CurrentScene) { bool shouldContinue = SceneUtil.SaveDirtyScenes(); if (!shouldContinue) { userAbortedSearch(); return; } } bool cancelled = false; try{ foreach (SearchSubJob subjob in subjobs) { for (int i = 0; i < 10; i++) { if (!cancelled) { cancelled = progress(); } while (!cancelled && subjob.SearchNextAsset()) { if (result.resultsCount > maxItemsAllowed && !shownMaxItemsWarning) { shownMaxItemsWarning = true; bool userContinues = EditorUtility.DisplayDialog("Too Many Results", "The search and replace plugin has found " + result.resultsCount + " results so far. Do you want to continue searching?", "Continue", "Cancel"); if (!userContinues) { cancelled = true; } } currentItem++; } } } }catch (System.Exception ex) { Debug.LogException(ex); result.status = SearchStatus.InProgress; result.statusMsg = "An exception occurred: " + ex.ToString(); EditorUtility.ClearProgressBar(); } EditorUtility.ClearProgressBar(); foreach (SearchSubJob subjob in subjobs) { subjob.JobDone(); } search.OnSearchEnd(this); if (cancelled) { userAbortedSearch(); } //calculate searchedItems int searchedItems = 0; foreach (var kvp in searchAssetsData) { SearchAssetData data = kvp.Value; if (data.searchExecuted) { searchedItems++; } } if (result.status == SearchStatus.InProgress) { //standard termination. result.searchedItems = searchedItems; result.status = SearchStatus.Complete; } result.OnSearchComplete(); string log = logBuilder.ToString(); if (log.Length > 0) { Debug.Log("[Search & Replace] Log:\n" + log); } }
//Instead of maintaining a separate hashset, we just put the internal asset //into the dictionary. public void addInternalAsset(string path, int instanceID) { SearchAssetData internalSearchObject = new SearchAssetData(path); searchAssetsData[path + instanceID] = internalSearchObject; }