private static bool OnPrefabGameObjectTraverse(ObjectTraverseInfo objectInfo) { #if !UNITY_2020_1_OR_NEWER if (currentObjectIndex % ObjectTraverseUpdateStep == 0) #endif { if (IssuesFinder.ShowProgressBar(2, 3, itemIndex, totalItems, string.Format("Processing prefab: {0}", currentAssetName))) { return(false); } } currentObjectIndex++; bool skipTree; if (IssuesDetector.StartGameObject(objectInfo.current, objectInfo.inPrefabInstance, out skipTree)) { CSTraverseTools.TraverseGameObjectComponents(objectInfo, OnComponentTraverse); IssuesDetector.EndGameObject(objectInfo.current); } objectInfo.skipCurrentTree = skipTree; return(true); }
public static List <IssueRecord> CheckSceneSettingsForMissingReferences(AssetInfo sceneAsset) { var result = new List <IssueRecord>(); var sceneSettingsObject = CSSettingsTools.GetInSceneLightmapSettings(); if (sceneSettingsObject != null) { var initialInfo = new SerializedObjectTraverseInfo(sceneSettingsObject); CSTraverseTools.TraverseObjectProperties(initialInfo, (info, property) => { if (MissingReferenceDetector.IsPropertyHasMissingReference(property)) { var record = SceneSettingsIssueRecord.Create(SceneSettingsKind.LightmapSettings, IssueKind.MissingReference, sceneAsset.Path, property.propertyPath); result.Add(record); } }); } sceneSettingsObject = CSSettingsTools.GetInSceneRenderSettings(); if (sceneSettingsObject != null) { var initialInfo = new SerializedObjectTraverseInfo(sceneSettingsObject); CSTraverseTools.TraverseObjectProperties(initialInfo, (info, property) => { if (MissingReferenceDetector.IsPropertyHasMissingReference(property)) { var record = SceneSettingsIssueRecord.Create(SceneSettingsKind.RenderSettings, IssueKind.MissingReference, sceneAsset.Path, property.propertyPath); result.Add(record); } }); } return(result); }
public void ProcessComponent(Component component, Type componentType) { if (!enabled) { return; } existingData = null; newHash = 0; if (!uniqueTypes.TryGetValue(componentType, out existingData)) { var newData = new List <ComponentDuplicateInfo>(); newData.Add(new ComponentDuplicateInfo(component)); uniqueTypes.Add(componentType, newData); } else { foreach (var duplicateInfo in existingData) { if (duplicateInfo.hash == 0) { var initialInfo = new SerializedObjectTraverseInfo(duplicateInfo.reference); var duplicateInfoInClosure = duplicateInfo; CSTraverseTools.TraverseObjectProperties(initialInfo, (info, property) => { duplicateInfoInClosure.hash += CSEditorTools.GetPropertyHash(property); }); } } existingData.Add(new ComponentDuplicateInfo(component)); } }
///////////////////////////////////////////////////////////////////////// // Scriptable Objects Processing ///////////////////////////////////////////////////////////////////////// public static void ProcessScriptableObject(AssetInfo asset, Object scriptableObject) { currentLocation = RecordLocation.Asset; if (missingComponentDetector.TryDetectScriptableObjectIssue(asset.Path, scriptableObject)) { return; } var shouldTraverseProperties = missingReferenceDetector.Enabled; if (shouldTraverseProperties) { var initialInfo = new SerializedObjectTraverseInfo(scriptableObject); CSTraverseTools.TraverseObjectProperties(initialInfo, (info, property) => { if (property.type == "UnityEvent") { missingReferenceDetector.TryDetectScriptableObjectUnityEventIssue(asset.Path, info.TraverseTarget.GetType().Name, property); info.skipCurrentTree = true; return; } missingReferenceDetector.TryDetectScriptableObjectIssue(asset.Path, info.TraverseTarget.GetType().Name, property); }); } currentLocation = RecordLocation.Unknown; }
private static void ProcessSceneForProjectLevelReferences(string path, List <TreeConjunction> conjunctions) { var openSceneResult = CSSceneTools.OpenScene(path); if (!openSceneResult.success) { Debug.LogWarning(Maintainer.ConstructWarning("Can't open scene " + path)); return; } SceneSettingsProcessor.Process(conjunctions); EntryFinder.currentLocation = Location.SceneGameObject; CSTraverseTools.TraverseSceneGameObjects(openSceneResult.scene, true, false, EntryFinder.OnGameObjectTraverse); CSSceneTools.CloseOpenedSceneIfNeeded(openSceneResult); }
public static List <IssueRecord> CheckSettingsAssetForMissingReferences(AssetInfo asset, AssetSettingsKind kind) { var result = new List <IssueRecord>(); // include only supported settings files with object references if (kind != AssetSettingsKind.EditorSettings && kind != AssetSettingsKind.GraphicsSettings && kind != AssetSettingsKind.DynamicsManager && kind != AssetSettingsKind.Physics2DSettings && kind != AssetSettingsKind.PresetManager && kind != AssetSettingsKind.VFXManager) { return(result); } var allAssets = AssetDatabase.LoadAllAssetsAtPath(asset.Path); if (allAssets == null || allAssets.Length <= 0) { return(result); } foreach (var assetObject in allAssets) { if (assetObject == null) { return(result); } var traverseInfo = new SerializedObjectTraverseInfo(assetObject); CSTraverseTools.TraverseObjectProperties(traverseInfo, (info, property) => { if (MissingReferenceDetector.IsPropertyHasMissingReference(property)) { var issue = SettingsIssueRecord.Create(kind, IssueKind.MissingReference, asset.Path, property.propertyPath); result.Add(issue); } }); } return(result); }
private static void ProcessScene() { var path = assetConjunctions.asset.Path; var openSceneResult = CSSceneTools.OpenScene(path); if (!openSceneResult.success) { Debug.LogWarning(Maintainer.ConstructWarning("Can't open scene " + path)); return; } SceneSettingsProcessor.Process(assetConjunctions.conjunctions); currentLocation = Location.SceneGameObject; CSTraverseTools.TraverseSceneGameObjects(openSceneResult.scene, true, OnGameObjectTraverse); CSSceneTools.CloseOpenedSceneIfNeeded(openSceneResult); }
private static void ProcessPrefab(AssetInfo asset, string assetName, int prefabIndex, int totalPrefabs) { currentObjectIndex = 0; itemIndex = prefabIndex; totalItems = totalPrefabs; currentAssetName = assetName; var prefabRootGameObject = CSPrefabTools.GetPrefabAssetRoot(asset.Path); if (prefabRootGameObject == null) { return; } IssuesDetector.StartPrefabAsset(asset); CSTraverseTools.TraversePrefabGameObjects(prefabRootGameObject, true, false, OnPrefabGameObjectTraverse); IssuesDetector.EndPrefabAsset(asset); }
private static bool OnGameObjectTraverse(ObjectTraverseInfo traverseInfo) { var target = traverseInfo.current; currentObjectCache = null; //Debug.Log("OnGameObjectTraverse " + target); if (traverseInfo.inPrefabInstance) { //Debug.Log("traverseInfo.dirtyComponents " + traverseInfo.dirtyComponents); var prefabAssetSource = CSPrefabTools.GetAssetSource(target); if (prefabAssetSource != null) { var instanceId = prefabAssetSource.GetInstanceID(); TryAddEntryToMatchedConjunctions(target, instanceId, null); if (traverseInfo.dirtyComponents == null) { traverseInfo.skipCurrentTree = true; return(true); } } } var thumbnail = AssetPreview.GetMiniThumbnail(target); if (thumbnail != null && (thumbnail.hideFlags & HideFlags.HideAndDontSave) == 0) { var addSettings = new EntryAddSettings { prefix = "[Object Icon]", }; TryAddEntryToMatchedConjunctions(target, thumbnail.GetInstanceID(), addSettings); } CSTraverseTools.TraverseGameObjectComponents(traverseInfo, OnGameObjectComponentTraverse); return(true); }
public static bool OnGameObjectTraverse(ObjectTraverseInfo traverseInfo) { var target = traverseInfo.current; //Debug.Log("OnGameObjectTraverse " + target); if (traverseInfo.inPrefabInstance) { var prefabAssetSource = CSPrefabTools.GetAssetSource(target); if (prefabAssetSource != null) { var instanceId = prefabAssetSource.GetInstanceID(); currentProcessReferenceCallback(target, instanceId, null); if (traverseInfo.dirtyComponents == null) { traverseInfo.skipCurrentTree = true; return true; } } } var thumbnail = AssetPreview.GetMiniThumbnail(target); if (thumbnail != null && (thumbnail.hideFlags & HideFlags.HideAndDontSave) == 0) { var addSettings = new EntryAddSettings { prefix = "[Object Icon]", }; currentProcessReferenceCallback(target, thumbnail.GetInstanceID(), addSettings); } CSTraverseTools.TraverseGameObjectComponents(traverseInfo, OnGameObjectComponentTraverse); return true; }
private static bool OnGameObjectTraverse(ObjectTraverseInfo objectInfo) { if (currentObjectIndex % ObjectTraverseUpdateStep == 0) { if (IssuesFinder.ShowProgressBar(1, 3, itemIndex, totalItems, string.Format("Processing scene: {0} root {1}/{2}", currentAssetName, objectInfo.rootIndex + 1, objectInfo.TotalRoots))) { return(false); } } currentObjectIndex++; bool skipTree; if (IssuesDetector.StartGameObject(objectInfo.current, objectInfo.inPrefabInstance, out skipTree)) { CSTraverseTools.TraverseGameObjectComponents(objectInfo, OnComponentTraverse); IssuesDetector.EndGameObject(objectInfo.current); } objectInfo.skipCurrentTree = skipTree; return(true); }
private static void ProcessScene(AssetInfo asset, string assetName, int sceneIndex, int totalScenes) { currentObjectIndex = 0; itemIndex = sceneIndex; totalItems = totalScenes; currentAssetName = assetName; var openSceneResult = CSSceneTools.OpenScene(asset.Path); if (!openSceneResult.success) { Debug.LogWarning(Maintainer.ConstructWarning("Can't open scene " + asset.Path)); return; } var skipCleanPrefabInstances = ProjectSettings.Issues.scanGameObjects && ProjectSettings.Issues.lookInAssets; IssuesDetector.SceneStart(asset); CSTraverseTools.TraverseSceneGameObjects(openSceneResult.scene, skipCleanPrefabInstances, false, OnGameObjectTraverse); IssuesDetector.SceneEnd(asset); CSSceneTools.CloseOpenedSceneIfNeeded(openSceneResult); }
public static void ProcessObject(Location currentLocation, Object inspectedUnityObject, Object target, EntryAddSettings addSettings, ProcessObjectReferenceHandler processReferenceCallback) { var onlyVisibleProperties = currentLocation != Location.ScriptAsset; var componentTraverseInfo = new SerializedObjectTraverseInfo(target, onlyVisibleProperties); string lastScriptPropertyName = null; CSTraverseTools.TraverseObjectProperties(componentTraverseInfo, (info, sp) => { if (currentLocation == Location.ScriptAsset) { if (sp.isArray) { if (sp.type == "string") { if (sp.propertyPath.IndexOf("m_DefaultReferences.Array.data[", StringComparison.OrdinalIgnoreCase) == 0) { if (sp.stringValue != null) { lastScriptPropertyName = sp.stringValue; // skipping first pair item of the m_DefaultReferences array item sp.Next(false); } } } } } if (sp.propertyType == SerializedPropertyType.ObjectReference && sp.objectReferenceValue != null) { string propertyName; if (lastScriptPropertyName != null) { propertyName = lastScriptPropertyName; lastScriptPropertyName = string.Empty; } else { propertyName = sp.propertyPath; } /*if (string.Equals(propertyName, "m_Script", StringComparison.OrdinalIgnoreCase)) * { * propertyName = "Script source"; * }*/ addSettings.propertyPath = propertyName; processReferenceCallback(inspectedUnityObject, sp.objectReferenceInstanceIDValue, addSettings); /* material instance handling */ var material = sp.objectReferenceValue as Material; if (material == null) { return; } if (currentLocation == Location.PrefabAssetGameObject) { if (AssetDatabase.GetAssetPath(material) != AssetDatabase.GetAssetPath(target)) { return; } if (AssetDatabase.IsSubAsset(material)) { return; } } else { if (AssetDatabase.Contains(material)) { return; } } addSettings.prefix = "[Material Instance]"; addSettings.suffix = "(Main Texture)"; var mainTextureInstanceId = 0; if (material.HasProperty(MainTextureShaderProperty)) { var mainTexture = material.mainTexture; mainTextureInstanceId = mainTexture != null ? mainTexture.GetInstanceID() : 0; } processReferenceCallback(inspectedUnityObject, mainTextureInstanceId, addSettings); addSettings.suffix = "(Shader)"; var shaderInstanceId = material.shader != null ? material.shader.GetInstanceID() : 0; processReferenceCallback(inspectedUnityObject, shaderInstanceId, addSettings); var materialSo = new SerializedObject(material); var texEnvs = materialSo.FindProperty("m_SavedProperties.m_TexEnvs.Array"); if (texEnvs != null) { for (var k = 0; k < texEnvs.arraySize; k++) { var arrayItem = texEnvs.GetArrayElementAtIndex(k); var fieldName = arrayItem.displayName; if (fieldName == MainTexturePropertyName) { continue; } var textureProperty = arrayItem.FindPropertyRelative("second.m_Texture"); if (textureProperty != null) { if (textureProperty.propertyType == SerializedPropertyType.ObjectReference) { addSettings.suffix = " (" + fieldName + ")"; processReferenceCallback(inspectedUnityObject, textureProperty.objectReferenceInstanceIDValue, addSettings); } } else { Debug.LogError(Maintainer.ConstructError("Can't get second.m_Texture from texEnvs at " + inspectedUnityObject.name)); } } } else { Debug.LogError(Maintainer.ConstructError("Can't get m_SavedProperties.m_TexEnvs.Array from material instance at " + inspectedUnityObject.name)); } } lastScriptPropertyName = null; }); }
private static void ProcessPrefab(string path) { var assetObject = AssetDatabase.LoadMainAssetAtPath(path); if (assetObject == null) { return; } var prefabRootGameObject = assetObject as GameObject; if (prefabRootGameObject == null) { return; } bool prefabOpened; var stageRoot = TryGetPrefabRootFromStage(path, assetObject, out prefabOpened); if (stageRoot != null) { prefabRootGameObject = stageRoot; } EntryFinder.currentLocation = Location.PrefabAssetGameObject; CSTraverseTools.TraversePrefabGameObjects(prefabRootGameObject, true, false, EntryFinder.OnGameObjectTraverse); // specific cases handling for main asset ----------------------------------------------------- /*var importSettings = AssetImporter.GetAtPath(path) as ModelImporter; * if (importSettings == null) return; * * var settings = new EntryAddSettings { suffix = "| Model Importer: RIG > Source" }; * TryAddEntryToMatchedConjunctions(assetConjunctions.conjunctions, prefabRootGameObject, importSettings.sourceAvatar, settings); * * for (var i = 0; i < importSettings.clipAnimations.Length; i++) * { * var clipAnimation = importSettings.clipAnimations[i]; * settings.suffix = "| Model Importer: Animations [" + clipAnimation.name + "] > Mask"; * TryAddEntryToMatchedConjunctions(assetConjunctions.conjunctions, prefabRootGameObject, clipAnimation.maskSource, settings); * }*/ var allObjectsInPrefab = AssetDatabase.LoadAllAssetsAtPath(path); foreach (var objectOnPrefab in allObjectsInPrefab) { if (objectOnPrefab == null) { continue; } if (objectOnPrefab is GameObject || objectOnPrefab is Component) { continue; } EntryFinder.currentLocation = Location.PrefabAssetObject; var addSettings = new EntryAddSettings(); EntryFinder.TraverseObjectProperties(objectOnPrefab, objectOnPrefab, addSettings); /*if (AssetDatabase.IsMainAsset(objectOnPrefab)) * { * * } * else*/ { // specific cases handling ------------------------------------------------------------------------ /*if (objectOnPrefab is BillboardAsset) * { * var billboardAsset = objectOnPrefab as BillboardAsset; * var settings = new EntryAddSettings { suffix = "| BillboardAsset: Material" }; * TryAddEntryToMatchedConjunctions(assetConjunctions.conjunctions, billboardAsset, billboardAsset.material, settings); * } * else if (objectOnPrefab is TreeData) * { * CachedObjectData objectInAssetCachedData = null; * InspectComponent(assetConjunctions.conjunctions, objectOnPrefab, objectOnPrefab, -1, true, ref objectInAssetCachedData); * }*/ } } if (prefabOpened) { StageUtility.GoBackToPreviousStage(); } }
/// <summary> /// Starts search with current settings. /// </summary> /// <param name="showResults">Shows results in the %Maintainer window if true.</param> /// <returns>Array of IssueRecords in case you wish to manually iterate over them and make custom report.</returns> public static IssueRecord[] StartSearch(bool showResults) { if (!ProjectSettings.Issues.lookInScenes && !ProjectSettings.Issues.lookInAssets && !ProjectSettings.Issues.lookInProjectSettings) { MaintainerWindow.ShowNotification("Nowhere to search!"); return(null); } if (ProjectSettings.Issues.lookInScenes) { if (!CSSceneTools.SaveCurrentModifiedScenes(false)) { Debug.Log(Maintainer.LogPrefix + "Issues search canceled by user!"); return(null); } } var issues = new List <IssueRecord>(); PrepareToBatchOperation(); try { var sw = Stopwatch.StartNew(); CSTraverseTools.ClearStats(); var targetAssets = TargetCollector.CollectTargetAssets(); /*foreach (var targetAsset in targetAssets) * { * Debug.Log(targetAsset.Path); * }*/ TargetProcessor.SetIssuesList(issues); TargetProcessor.ProcessTargetAssets(targetAssets); var traverseStats = CSTraverseTools.GetStats(); var checkedAssets = targetAssets.Length; sw.Stop(); if (!operationCanceled) { var result = string.Format(CultureInfo.InvariantCulture, Maintainer.LogPrefix + ModuleName + " found issues: {0}\n" + "Seconds: {1:0.000}; Assets: {2}; Game Objects: {3}; Components: {4}; Properties: {5}", issues.Count, sw.Elapsed.TotalSeconds, checkedAssets, traverseStats.gameObjectsTraversed, traverseStats.componentsTraversed, traverseStats.propertiesTraversed); Debug.Log(result); } else { Debug.Log(Maintainer.LogPrefix + "Search canceled by user!"); } SearchResultsStorage.IssuesSearchResults = issues.ToArray(); if (showResults) { MaintainerWindow.ShowIssues(); } } catch (Exception e) { Debug.LogError(Maintainer.LogPrefix + ModuleName + ": something went wrong :(\n" + e); } EditorUtility.ClearProgressBar(); return(issues.ToArray()); }
///////////////////////////////////////////////////////////////////////// // Game Object's Components Processing ///////////////////////////////////////////////////////////////////////// public static void ProcessComponent(Component component, int orderIndex) { #if !UNITY_2019_1_OR_NEWER if (missingComponentDetector.CheckAndRecordNullComponent(component)) { return; } #else if (component == null) { return; } #endif if ((component.hideFlags & HideFlags.HideInInspector) != 0) { return; } if (!MaintainerSettings.Issues.touchDisabledComponents) { if (EditorUtility.GetObjectEnabled(component) == 0) { return; } } var componentType = component.GetType(); var componentName = componentType.Name; if (MaintainerSettings.Issues.componentIgnoresFilters != null && MaintainerSettings.Issues.componentIgnoresFilters.Length > 0) { if (CSFilterTools.IsValueMatchesAnyFilterOfKind(componentName, MaintainerSettings.Issues.componentIgnoresFilters, FilterKind.Type)) { return; } } duplicateComponentDetector.ProcessComponent(component, componentType); var shouldCheckPropertiesForDuplicate = duplicateComponentDetector.IsPropertiesHashCalculationRequired(); if (shouldCheckPropertiesForDuplicate) { // skipping duplicate search for non-standard components with invisible properties var baseType = componentType.BaseType; if (baseType != null) { if (baseType.Name == "MegaModifier") { shouldCheckPropertiesForDuplicate = false; duplicateComponentDetector.SkipComponent(); } } } var shouldTraverseProperties = missingReferenceDetector.Enabled || shouldCheckPropertiesForDuplicate; if (shouldTraverseProperties) { var initialInfo = new SerializedObjectTraverseInfo(component); CSTraverseTools.TraverseObjectProperties(initialInfo, (info, property) => { if (property.type == "UnityEvent") { missingReferenceDetector.TryDetectUnityEventIssues(currentLocation, currentAsset.Path, currentGameObject, componentType, componentName, orderIndex, property); info.skipCurrentTree = true; return; } missingReferenceDetector.TryDetectIssue(currentLocation, currentAsset.Path, currentGameObject, componentType, componentName, orderIndex, property); if (shouldCheckPropertiesForDuplicate) { duplicateComponentDetector.ProcessProperty(property); } }); } if (shouldCheckPropertiesForDuplicate) { duplicateComponentDetector.TryDetectIssue(currentLocation, currentAsset.Path, currentGameObject, componentType, componentName, orderIndex); } if (component is Terrain) { inconsistentTerrainDataDetector.ProcessTerrainComponent((Terrain)component, componentType, componentName, orderIndex); } else if (component is TerrainCollider) { inconsistentTerrainDataDetector.ProcessTerrainColliderComponent((TerrainCollider)component); } //Debug.Log("ProcessComponent: " + target.name + ":" + component); }
private static bool ProcessSceneForSceneScopeReferences(GameObject[] rootObjects) { EntryFinder.currentLocation = Location.SceneGameObject; return(!CSTraverseTools.TraverseRootGameObjects(rootObjects, false, true, EntryFinder.OnGameObjectTraverse, OnRootTraverse)); }
private static bool ProcessPrefabForSceneScopeReferences(PrefabStage prefabStage) { EntryFinder.currentLocation = Location.PrefabAssetGameObject; return(!CSTraverseTools.TraversePrefabGameObjects(prefabStage.prefabContentsRoot, false, true, EntryFinder.OnGameObjectTraverse)); }