WuhuIslandTesting/Library/PackageCache/com.unity.addressables@1.21.12/Editor/GUI/AssetSettingsAnalyzeTreeView.cs
2025-01-07 02:06:59 +01:00

533 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.AddressableAssets.Build;
using UnityEditor.AddressableAssets.Build.AnalyzeRules;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
namespace UnityEditor.AddressableAssets.GUI
{
class AssetSettingsAnalyzeTreeView : TreeView
{
private int m_CurrentDepth;
internal AssetSettingsAnalyzeTreeView(TreeViewState state)
: base(state)
{
showAlternatingRowBackgrounds = true;
showBorder = true;
Reload();
}
private List<AnalyzeRuleContainerTreeViewItem> GatherAllInheritRuleContainers(TreeViewItem baseContainer)
{
List<AnalyzeRuleContainerTreeViewItem> retValue = new List<AnalyzeRuleContainerTreeViewItem>();
if (!baseContainer.hasChildren)
return new List<AnalyzeRuleContainerTreeViewItem>();
foreach (var child in baseContainer.children)
{
if (child is AnalyzeRuleContainerTreeViewItem)
{
retValue.AddRange(GatherAllInheritRuleContainers(child as AnalyzeRuleContainerTreeViewItem));
retValue.Add(child as AnalyzeRuleContainerTreeViewItem);
}
}
return retValue;
}
private void PerformActionForEntireRuleSelection(Action<AnalyzeRuleContainerTreeViewItem> action)
{
List<AnalyzeRuleContainerTreeViewItem> activeSelection = (from id in GetSelection()
let selection = FindItem(id, rootItem)
where selection is AnalyzeRuleContainerTreeViewItem
select selection as AnalyzeRuleContainerTreeViewItem).ToList();
PerformActionForRuleItems(action, activeSelection);
}
private void PerformActionForRuleItems(Action<AnalyzeRuleContainerTreeViewItem> action, List<AnalyzeRuleContainerTreeViewItem> activeSelection)
{
List<AnalyzeRuleContainerTreeViewItem> inheritSelection = new List<AnalyzeRuleContainerTreeViewItem>();
foreach (var selected in activeSelection)
inheritSelection.AddRange(GatherAllInheritRuleContainers(selected));
List<AnalyzeRuleContainerTreeViewItem> entireSelection = activeSelection.Union(inheritSelection).ToList();
foreach (AnalyzeRuleContainerTreeViewItem ruleContainer in entireSelection)
{
if (ruleContainer.analyzeRule != null)
{
action(ruleContainer);
}
}
}
public void RunAllSelectedRules()
{
PerformActionForEntireRuleSelection((ruleContainer) =>
{
var results = AnalyzeSystem.RefreshAnalysis(ruleContainer.analyzeRule);
BuildResults(ruleContainer, results);
Reload();
UpdateSelections(GetSelection());
});
}
public void FixAllSelectedRules()
{
PerformActionForEntireRuleSelection((ruleContainer) =>
{
AnalyzeSystem.FixIssues(ruleContainer.analyzeRule);
var results = AnalyzeSystem.RefreshAnalysis(ruleContainer.analyzeRule);
BuildResults(ruleContainer, results);
Reload();
UpdateSelections(GetSelection());
});
}
public void ClearAll()
{
var root = rootItem.children[0] as AnalyzeRuleContainerTreeViewItem;
if (root == null)
{
Debug.LogError("Error: Structure of AnalyzeRule tree view is different to expected.");
return;
}
List<AnalyzeRuleContainerTreeViewItem> activeSelection = new List<AnalyzeRuleContainerTreeViewItem>(1);
activeSelection.Add(root);
PerformActionForRuleItems((ruleContainer) =>
{
AnalyzeSystem.ClearAnalysis(ruleContainer.analyzeRule);
BuildResults(ruleContainer, new List<AnalyzeRule.AnalyzeResult>());
}, activeSelection);
Reload();
UpdateSelections(GetSelection());
}
public void ClearAllSelectedRules()
{
PerformActionForEntireRuleSelection((ruleContainer) =>
{
AnalyzeSystem.ClearAnalysis(ruleContainer.analyzeRule);
BuildResults(ruleContainer, new List<AnalyzeRule.AnalyzeResult>());
});
Reload();
UpdateSelections(GetSelection());
}
public bool SelectionContainsFixableRule { get; private set; }
public bool SelectionContainsRuleContainer { get; private set; }
public bool SelectionContainsErrors { get; private set; }
protected override void SelectionChanged(IList<int> selectedIds)
{
UpdateSelections(selectedIds);
}
void UpdateSelections(IList<int> selectedIds)
{
var allSelectedRuleContainers = (from id in selectedIds
let ruleContainer = FindItem(id, rootItem) as AnalyzeRuleContainerTreeViewItem
where ruleContainer != null
select ruleContainer);
List<AnalyzeRuleContainerTreeViewItem> allRuleContainers = new List<AnalyzeRuleContainerTreeViewItem>();
foreach (var ruleContainer in allSelectedRuleContainers)
{
allRuleContainers.AddRange(GatherAllInheritRuleContainers(ruleContainer));
allRuleContainers.Add(ruleContainer);
}
allRuleContainers = allRuleContainers.Distinct().ToList();
SelectionContainsErrors = (from container in allRuleContainers
from child in container.children
where child is AnalyzeResultsTreeViewItem && (child as AnalyzeResultsTreeViewItem).IsError
select child).Any();
SelectionContainsRuleContainer = allRuleContainers.Any();
SelectionContainsFixableRule = (from container in allRuleContainers
where container.analyzeRule.CanFix
select container).Any();
}
protected override void ContextClicked()
{
if (SelectionContainsRuleContainer)
{
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Run Analyze Rule"), false, RunAllSelectedRules);
menu.AddItem(new GUIContent("Clear Analyze Results"), false, ClearAllSelectedRules);
if (SelectionContainsFixableRule && SelectionContainsErrors)
menu.AddItem(new GUIContent("Fix Analyze Rule"), false, FixAllSelectedRules);
else
menu.AddDisabledItem(new GUIContent("Fix Analyze Rule"));
IList<int> selectedIds = GetSelection();
if (selectedIds.Count == 1)
{
AnalyzeRuleContainerTreeViewItem analyzeRuleContainer = FindItem(selectedIds[0], rootItem) as AnalyzeRuleContainerTreeViewItem;
if (analyzeRuleContainer != null)
{
foreach (var customMenuItem in analyzeRuleContainer.analyzeRule.GetCustomContextMenuItems())
{
if (customMenuItem.MenuEnabled)
menu.AddItem(new GUIContent(customMenuItem.MenuName), customMenuItem.ToggledOn, () => customMenuItem.MenuAction());
else
menu.AddDisabledItem(new GUIContent(customMenuItem.MenuName));
}
}
}
menu.ShowAsContext();
Repaint();
}
else
{
var selectedIds = this.GetSelection();
List<AnalyzeResultsTreeViewItem> items = new List<AnalyzeResultsTreeViewItem>();
foreach (int id in selectedIds)
{
var item = FindItem(id, rootItem) as AnalyzeResultsTreeViewItem;
if (item != null)
items.Add(item);
}
if (items.Count > 0)
AnalyzeResultsTreeViewItem.ContextClicked(items);
}
}
protected override void DoubleClickedItem(int id)
{
var item = FindItem(id, rootItem) as AnalyzeResultsTreeViewItem;
if (item != null)
item.DoubleClicked();
}
protected override TreeViewItem BuildRoot()
{
m_CurrentDepth = 0;
var root = new TreeViewItem(-1, -1);
root.children = new List<TreeViewItem>();
string baseName = "Analyze Rules";
string fixableRules = "Fixable Rules";
string unfixableRules = "Unfixable Rules";
AnalyzeSystem.TreeView = this;
AnalyzeRuleContainerTreeViewItem baseViewItem = new AnalyzeRuleContainerTreeViewItem(baseName.GetHashCode(), m_CurrentDepth, baseName);
baseViewItem.children = new List<TreeViewItem>();
baseViewItem.analyzeRule.CanFix = true;
root.AddChild(baseViewItem);
m_CurrentDepth++;
var fixable = new AnalyzeRuleContainerTreeViewItem(fixableRules.GetHashCode(), m_CurrentDepth, fixableRules);
var unfixable = new AnalyzeRuleContainerTreeViewItem(unfixableRules.GetHashCode(), m_CurrentDepth, unfixableRules);
fixable.analyzeRule.CanFix = true;
unfixable.analyzeRule.CanFix = false;
baseViewItem.AddChild(fixable);
baseViewItem.AddChild(unfixable);
m_CurrentDepth++;
for (int i = 0; i < AnalyzeSystem.Rules.Count; i++)
{
AnalyzeRuleContainerTreeViewItem ruleContainer = new AnalyzeRuleContainerTreeViewItem(
AnalyzeSystem.Rules[i].ruleName.GetHashCode(), m_CurrentDepth, AnalyzeSystem.Rules[i]);
if (ruleContainer.analyzeRule.CanFix)
fixable.AddChild(ruleContainer);
else
unfixable.AddChild(ruleContainer);
}
m_CurrentDepth++;
int index = 0;
var ruleContainers = GatherAllInheritRuleContainers(baseViewItem);
foreach (var ruleContainer in ruleContainers)
{
if (ruleContainer == null)
continue;
EditorUtility.DisplayProgressBar("Calculating Analyze Results...", ruleContainer.displayName, (index / (float)ruleContainers.Count));
if (AnalyzeSystem.AnalyzeData.Data.ContainsKey(ruleContainer.analyzeRule.ruleName))
BuildResults(ruleContainer, AnalyzeSystem.AnalyzeData.Data[ruleContainer.analyzeRule.ruleName]);
index++;
}
EditorUtility.ClearProgressBar();
return root;
}
private readonly Dictionary<int, AnalyzeResultsTreeViewItem> hashToAnalyzeResults = new Dictionary<int, AnalyzeResultsTreeViewItem>();
void BuildResults(TreeViewItem root, List<AnalyzeRule.AnalyzeResult> ruleResults)
{
hashToAnalyzeResults.Clear();
int updateFrequency = Mathf.Max(ruleResults.Count / 10, 1);
for (int index = 0; index < ruleResults.Count; ++index)
{
var result = ruleResults[index];
if (index == 0 || index % updateFrequency == 0)
EditorUtility.DisplayProgressBar("Building Results Tree...", result.resultName, (float)index / hashToAnalyzeResults.Keys.Count);
var resPath = result.resultName.Split(AnalyzeRule.kDelimiter);
string name = string.Empty;
TreeViewItem parent = root;
for (int i = 0; i < resPath.Length; i++)
{
name += resPath[i];
int hash = name.GetHashCode();
if (!hashToAnalyzeResults.ContainsKey(hash))
{
AnalyzeResultsTreeViewItem item = new AnalyzeResultsTreeViewItem(hash, i + m_CurrentDepth, resPath[i], result.severity, result);
hashToAnalyzeResults.Add(item.id, item);
parent.AddChild(item);
parent = item;
}
else
{
var targetItem = hashToAnalyzeResults[hash];
targetItem.results.Add(result);
parent = targetItem;
}
}
}
EditorUtility.ClearProgressBar();
List<TreeViewItem> allTreeViewItems = new List<TreeViewItem>();
allTreeViewItems.Add(root);
allTreeViewItems.AddRange(root.children);
foreach (var node in allTreeViewItems)
(node as AnalyzeTreeViewItemBase)?.AddIssueCountToName();
AnalyzeSystem.SerializeData();
}
protected override void RowGUI(RowGUIArgs args)
{
var item = args.item as AnalyzeResultsTreeViewItem;
if (item != null && item.severity != MessageType.None)
{
Texture2D icon = null;
switch (item.severity)
{
case MessageType.Info:
icon = GetInfoIcon();
break;
case MessageType.Warning:
icon = GetWarningIcon();
break;
case MessageType.Error:
icon = GetErrorIcon();
break;
}
UnityEngine.GUI.Label(
new Rect(args.rowRect.x + baseIndent, args.rowRect.y, args.rowRect.width - baseIndent,
args.rowRect.height), new GUIContent(icon, string.Empty));
}
base.RowGUI(args);
}
Texture2D m_ErrorIcon;
Texture2D m_WarningIcon;
Texture2D m_InfoIcon;
Texture2D GetErrorIcon()
{
if (m_ErrorIcon == null)
FindMessageIcons();
return m_ErrorIcon;
}
Texture2D GetWarningIcon()
{
if (m_WarningIcon == null)
FindMessageIcons();
return m_WarningIcon;
}
Texture2D GetInfoIcon()
{
if (m_InfoIcon == null)
FindMessageIcons();
return m_InfoIcon;
}
void FindMessageIcons()
{
m_ErrorIcon = EditorGUIUtility.FindTexture("console.errorIcon");
m_WarningIcon = EditorGUIUtility.FindTexture("console.warnicon");
m_InfoIcon = EditorGUIUtility.FindTexture("console.infoIcon");
}
}
class AnalyzeTreeViewItemBase : TreeViewItem
{
private string baseDisplayName;
private string currentDisplayName;
public override string displayName
{
get { return currentDisplayName; }
set { baseDisplayName = value; }
}
public AnalyzeTreeViewItemBase(int id, int depth, string displayName) : base(id, depth,
displayName)
{
currentDisplayName = baseDisplayName = displayName;
}
public int AddIssueCountToName()
{
int issueCount = 0;
if (children != null)
{
foreach (var child in children)
{
var analyzeNode = child as AnalyzeResultsTreeViewItem;
if (analyzeNode != null)
issueCount += analyzeNode.AddIssueCountToName();
}
}
if (issueCount == 0)
return 1;
currentDisplayName = baseDisplayName + " (" + issueCount + ")";
return issueCount;
}
}
class AnalyzeResultsTreeViewItem : AnalyzeTreeViewItemBase
{
public MessageType severity { get; set; }
public HashSet<AnalyzeRule.AnalyzeResult> results { get; }
public bool IsError
{
get { return !AddressableAssetUtility.StringContains(displayName, "No issues found", StringComparison.Ordinal); }
}
public AnalyzeResultsTreeViewItem(int id, int depth, string displayName, MessageType type)
: base(id, depth, displayName)
{
severity = type;
results = new HashSet<AnalyzeRule.AnalyzeResult>();
}
public AnalyzeResultsTreeViewItem(int id, int depth, string displayName, MessageType type, AnalyzeRule.AnalyzeResult analyzeResult)
: base(id, depth, displayName)
{
severity = type;
results = new HashSet<AnalyzeRule.AnalyzeResult>() {analyzeResult};
}
internal static void ContextClicked(List<AnalyzeResultsTreeViewItem> items)
{
HashSet<UnityEngine.Object> objects = new HashSet<Object>();
foreach (AnalyzeResultsTreeViewItem viewItem in items)
{
foreach (var itemResult in viewItem.results)
{
Object o = GetResultObject(itemResult.resultName);
if (o != null)
objects.Add(o);
}
}
if (objects.Count > 0)
{
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent(objects.Count > 0 ? "Select Assets" : "Select Asset"), false, () =>
{
Selection.objects = objects.ToArray();
foreach (Object o in objects)
EditorGUIUtility.PingObject(o);
});
menu.ShowAsContext();
}
}
static UnityEngine.Object GetResultObject(string resultName)
{
int li = resultName.LastIndexOf(AnalyzeRule.kDelimiter);
if (li >= 0)
{
string assetPath = resultName.Substring(li + 1);
string guid = AssetDatabase.AssetPathToGUID(assetPath);
if (!string.IsNullOrEmpty(guid))
return AssetDatabase.LoadMainAssetAtPath(assetPath);
}
return null;
}
internal void DoubleClicked()
{
HashSet<UnityEngine.Object> objects = new HashSet<Object>();
foreach (var itemResult in results)
{
Object o = GetResultObject(itemResult.resultName);
if (o != null)
objects.Add(o);
}
if (objects.Count > 0)
{
Selection.objects = objects.ToArray();
foreach (Object o in objects)
EditorGUIUtility.PingObject(o);
}
}
}
class AnalyzeRuleContainerTreeViewItem : AnalyzeTreeViewItemBase
{
internal AnalyzeRule analyzeRule;
public AnalyzeRuleContainerTreeViewItem(int id, int depth, AnalyzeRule rule) : base(id, depth, rule.ruleName)
{
analyzeRule = rule;
children = new List<TreeViewItem>();
}
public AnalyzeRuleContainerTreeViewItem(int id, int depth, string displayName) : base(id, depth, displayName)
{
analyzeRule = new AnalyzeRule();
children = new List<TreeViewItem>();
}
}
}