WuhuIslandTesting/Library/PackageCache/com.unity.addressables@1.21.12/Editor/GUI/AssetInspectorGUI.cs

491 lines
23 KiB
C#
Raw Normal View History

2025-01-07 02:06:59 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.AddressableAssets.Build;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
using UnityEngine.TestTools;
namespace UnityEditor.AddressableAssets.GUI
{
using Object = UnityEngine.Object;
[InitializeOnLoad, ExcludeFromCoverage]
internal static class AddressableAssetInspectorGUI
{
static GUIStyle s_ToggleMixed;
static GUIContent s_AddressableAssetToggleText;
static GUIContent s_SystemSettingsGUIContent = new GUIContent("System Settings", "View Addressable Asset Settings");
static GUIContent s_GroupsDropdownLabelContent = new GUIContent("Group", "The Addressable Group that this asset is assigned to.");
static string s_GroupsDropdownControlName = nameof(AddressableAssetInspectorGUI) + ".GroupsPopupField";
static Texture s_GroupsCaretTexture = null;
static Texture s_FolderTexture = null;
static AddressableAssetInspectorGUI()
{
s_ToggleMixed = null;
s_AddressableAssetToggleText = new GUIContent("Addressable",
"Check this to mark this asset as an Addressable Asset, which includes it in the bundled data and makes it loadable via script by its address.");
Editor.finishedDefaultHeaderGUI += OnPostHeaderGUI;
}
static void SetAaEntry(AddressableAssetSettings aaSettings, List<TargetInfo> targetInfos, bool create)
{
if (create && aaSettings.DefaultGroup.ReadOnly)
{
Debug.LogError("Current default group is ReadOnly. Cannot add addressable assets to it");
return;
}
Undo.RecordObject(aaSettings, "AddressableAssetSettings");
if (!create)
{
List<AddressableAssetEntry> removedEntries = new List<AddressableAssetEntry>(targetInfos.Count);
for (int i = 0; i < targetInfos.Count; ++i)
{
AddressableAssetEntry e = aaSettings.FindAssetEntry(targetInfos[i].Guid);
AddressableAssetUtility.OpenAssetIfUsingVCIntegration(e.parentGroup);
removedEntries.Add(e);
aaSettings.RemoveAssetEntry(removedEntries[i], false);
}
if (removedEntries.Count > 0)
aaSettings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryRemoved, removedEntries, true, false);
}
else
{
AddressableAssetGroup parentGroup = aaSettings.DefaultGroup;
var resourceTargets = targetInfos.Where(ti => AddressableAssetUtility.IsInResources(ti.Path));
if (resourceTargets.Any())
{
var resourcePaths = resourceTargets.Select(t => t.Path).ToList();
var resourceGuids = resourceTargets.Select(t => t.Guid).ToList();
AddressableAssetUtility.SafeMoveResourcesToGroup(aaSettings, parentGroup, resourcePaths, resourceGuids);
}
var otherTargetInfos = targetInfos.Except(resourceTargets);
List<string> otherTargetGuids = new List<string>(targetInfos.Count);
foreach (var info in otherTargetInfos)
otherTargetGuids.Add(info.Guid);
var entriesCreated = new List<AddressableAssetEntry>();
var entriesMoved = new List<AddressableAssetEntry>();
aaSettings.CreateOrMoveEntries(otherTargetGuids, parentGroup, entriesCreated, entriesMoved, false, false);
bool openedInVC = false;
if (entriesMoved.Count > 0)
{
AddressableAssetUtility.OpenAssetIfUsingVCIntegration(parentGroup);
openedInVC = true;
aaSettings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesMoved, true, false);
}
if (entriesCreated.Count > 0)
{
if (!openedInVC)
AddressableAssetUtility.OpenAssetIfUsingVCIntegration(parentGroup);
aaSettings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryAdded, entriesCreated, true, false);
}
}
}
[UnityEngine.TestTools.ExcludeFromCoverage]
static void OnPostHeaderGUI(Editor editor)
{
var aaSettings = AddressableAssetSettingsDefaultObject.Settings;
if (editor.targets.Length > 0)
{
// only display for the Prefab/Model importer not the displayed GameObjects
if (editor.targets[0].GetType() == typeof(GameObject))
return;
foreach (var t in editor.targets)
{
if (t is AddressableAssetGroupSchema)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Profile: " + AddressableAssetSettingsDefaultObject.GetSettings(true).profileSettings
.GetProfileName(AddressableAssetSettingsDefaultObject.GetSettings(true).activeProfileId));
GUILayout.FlexibleSpace();
if (GUILayout.Button(s_SystemSettingsGUIContent, "MiniButton"))
{
EditorGUIUtility.PingObject(AddressableAssetSettingsDefaultObject.Settings);
Selection.activeObject = AddressableAssetSettingsDefaultObject.Settings;
}
GUILayout.EndHorizontal();
return;
}
}
List<TargetInfo> targetInfos = GatherTargetInfos(editor.targets, aaSettings);
if (targetInfos.Count == 0)
return;
bool targetHasAddressableSubObject = false;
int mainAssetsAddressable = 0;
int subAssetsAddressable = 0;
foreach (TargetInfo info in targetInfos)
{
if (info.MainAssetEntry == null)
continue;
if (info.MainAssetEntry.IsSubAsset)
subAssetsAddressable++;
else
mainAssetsAddressable++;
if (!info.IsMainAsset)
targetHasAddressableSubObject = true;
}
// Overrides a DisabledScope in the EditorElement.cs that disables GUI drawn in the header when the asset cannot be edited.
bool prevEnabledState = UnityEngine.GUI.enabled;
if (targetHasAddressableSubObject)
UnityEngine.GUI.enabled = false;
else
{
UnityEngine.GUI.enabled = true;
foreach (var info in targetInfos)
{
if (!info.IsMainAsset)
{
UnityEngine.GUI.enabled = false;
break;
}
}
}
int totalAddressableCount = mainAssetsAddressable + subAssetsAddressable;
if (totalAddressableCount == 0) // nothing is addressable
{
if (GUILayout.Toggle(false, s_AddressableAssetToggleText, GUILayout.ExpandWidth(false)))
SetAaEntry(AddressableAssetSettingsDefaultObject.GetSettings(true), targetInfos, true);
}
else if (totalAddressableCount == editor.targets.Length) // everything is addressable
{
var entryInfo = targetInfos[targetInfos.Count - 1];
if (entryInfo == null || entryInfo.MainAssetEntry == null)
throw new NullReferenceException("EntryInfo incorrect for Addressables content.");
GUILayout.BeginHorizontal();
if (mainAssetsAddressable > 0 && subAssetsAddressable > 0)
{
if (s_ToggleMixed == null)
s_ToggleMixed = new GUIStyle("ToggleMixed");
if (GUILayout.Toggle(false, s_AddressableAssetToggleText, s_ToggleMixed, GUILayout.ExpandWidth(false)))
SetAaEntry(aaSettings, targetInfos, true);
}
else if (mainAssetsAddressable > 0)
{
if (!GUILayout.Toggle(true, s_AddressableAssetToggleText, GUILayout.ExpandWidth(false)))
{
SetAaEntry(aaSettings, targetInfos, false);
UnityEngine.GUI.enabled = prevEnabledState;
GUIUtility.ExitGUI();
}
}
else if (GUILayout.Toggle(false, s_AddressableAssetToggleText, GUILayout.ExpandWidth(false)))
SetAaEntry(aaSettings, targetInfos, true);
if (editor.targets.Length == 1)
{
if (!entryInfo.IsMainAsset || entryInfo.MainAssetEntry.IsSubAsset)
{
bool preAddressPrevEnabledState = UnityEngine.GUI.enabled;
UnityEngine.GUI.enabled = false;
string address = entryInfo.Address + (entryInfo.IsMainAsset ? "" : $"[{entryInfo.TargetObject.name}]");
EditorGUILayout.DelayedTextField(address, GUILayout.ExpandWidth(true));
UnityEngine.GUI.enabled = preAddressPrevEnabledState;
}
else
{
string newAddress = EditorGUILayout.DelayedTextField(entryInfo.Address, GUILayout.ExpandWidth(true));
if (newAddress != entryInfo.Address)
{
if (newAddress.Contains('[') && newAddress.Contains(']'))
Debug.LogErrorFormat("Rename of address '{0}' cannot contain '[ ]'.", entryInfo.Address);
else
{
entryInfo.MainAssetEntry.address = newAddress;
AddressableAssetUtility.OpenAssetIfUsingVCIntegration(entryInfo.MainAssetEntry.parentGroup, true);
}
}
}
}
else
{
FindUniqueAssetGuids(targetInfos, out var uniqueAssetGuids, out var uniqueAddressableAssetGuids);
EditorGUILayout.LabelField(uniqueAddressableAssetGuids.Count + " out of " + uniqueAssetGuids.Count + " assets are addressable.");
}
DrawSelectEntriesButton(targetInfos);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
DrawGroupsDropdown(aaSettings, targetInfos);
GUILayout.EndHorizontal();
}
else // mixed addressable selected
{
GUILayout.BeginHorizontal();
if (s_ToggleMixed == null)
s_ToggleMixed = new GUIStyle("ToggleMixed");
if (GUILayout.Toggle(false, s_AddressableAssetToggleText, s_ToggleMixed, GUILayout.ExpandWidth(false)))
SetAaEntry(AddressableAssetSettingsDefaultObject.GetSettings(true), targetInfos, true);
FindUniqueAssetGuids(targetInfos, out var uniqueAssetGuids, out var uniqueAddressableAssetGuids);
EditorGUILayout.LabelField(uniqueAddressableAssetGuids.Count + " out of " + uniqueAssetGuids.Count + " assets are addressable.");
DrawSelectEntriesButton(targetInfos);
GUILayout.EndHorizontal();
}
UnityEngine.GUI.enabled = prevEnabledState;
}
}
// Caching due to Gathering TargetInfos is an expensive operation
// The InspectorGUI needs to call this multiple times per layout and paint
private static AddressableAssetSettings.Cache<int, List<TargetInfo>> s_Cache = null;
internal static List<TargetInfo> GatherTargetInfos(Object[] targets, AddressableAssetSettings aaSettings)
{
int selectionHashCode = targets[0].GetHashCode();
for (int i = 1; i < targets.Length; ++i)
selectionHashCode = selectionHashCode * 31 ^ targets[i].GetHashCode();
List<TargetInfo> targetInfos = null;
if (s_Cache == null && aaSettings != null)
s_Cache = new AddressableAssetSettings.Cache<int, List<TargetInfo>>(aaSettings);
if (s_Cache != null && s_Cache.TryGetCached(selectionHashCode, out targetInfos))
return targetInfos;
targetInfos = new List<TargetInfo>(targets.Length);
AddressableAssetEntry entry;
foreach (var t in targets)
{
if (AddressableAssetUtility.TryGetPathAndGUIDFromTarget(t, out var path, out var guid))
{
var mainAssetType = AssetDatabase.GetMainAssetTypeAtPath(path);
// Is asset
if (mainAssetType != null && !BuildUtility.IsEditorAssembly(mainAssetType.Assembly))
{
bool isMainAsset = t is AssetImporter || AssetDatabase.IsMainAsset(t);
var info = new TargetInfo() {TargetObject = t, Guid = guid, Path = path, IsMainAsset = isMainAsset};
if (aaSettings != null)
{
entry = aaSettings.FindAssetEntry(guid, true);
if (entry != null)
info.MainAssetEntry = entry;
}
targetInfos.Add(info);
}
}
}
if (s_Cache != null && targetInfos != null && targetInfos.Count > 0)
s_Cache.Add(selectionHashCode, targetInfos);
return targetInfos;
}
internal static void FindUniqueAssetGuids(List<TargetInfo> targetInfos, out HashSet<string> uniqueAssetGuids, out HashSet<string> uniqueAddressableAssetGuids)
{
uniqueAssetGuids = new HashSet<string>();
uniqueAddressableAssetGuids = new HashSet<string>();
foreach (TargetInfo info in targetInfos)
{
uniqueAssetGuids.Add(info.Guid);
if (info.MainAssetEntry != null)
uniqueAddressableAssetGuids.Add(info.Guid);
}
}
static void DrawSelectEntriesButton(List<TargetInfo> targets)
{
var prevGuiEnabled = UnityEngine.GUI.enabled;
UnityEngine.GUI.enabled = true;
if (GUILayout.Button("Select"))
{
AddressableAssetsWindow.Init();
var window = EditorWindow.GetWindow<AddressableAssetsWindow>();
List<AddressableAssetEntry> entries = new List<AddressableAssetEntry>(targets.Count);
foreach (TargetInfo info in targets)
{
if (info.MainAssetEntry != null)
{
if (info.IsMainAsset == false && ProjectConfigData.ShowSubObjectsInGroupView)
{
List<AddressableAssetEntry> subs = new List<AddressableAssetEntry>();
info.MainAssetEntry.GatherAllAssets(subs, false, true, true);
foreach (AddressableAssetEntry sub in subs)
{
if (sub.TargetAsset == info.TargetObject)
{
entries.Add(sub);
break;
}
}
}
else
entries.Add(info.MainAssetEntry);
}
}
if (entries.Count > 0)
window.SelectAssetsInGroupEditor(entries);
}
UnityEngine.GUI.enabled = prevGuiEnabled;
}
static void DrawGroupsDropdown(AddressableAssetSettings settings, List<TargetInfo> targets)
{
bool canEditGroup = true;
bool mixedGroups = false;
AddressableAssetGroup displayGroup = null;
var entries = new List<AddressableAssetEntry>();
foreach (TargetInfo info in targets)
{
AddressableAssetEntry entry = info.MainAssetEntry;
if (entry == null)
{
canEditGroup = false;
}
else
{
entries.Add(entry);
if (entry.ReadOnly || entry.parentGroup.ReadOnly)
{
canEditGroup = false;
}
if (displayGroup == null)
displayGroup = entry.parentGroup;
else if (entry.parentGroup != displayGroup)
{
mixedGroups = true;
}
}
}
using (new EditorGUI.DisabledScope(!canEditGroup))
{
GUILayout.Label(s_GroupsDropdownLabelContent);
if (mixedGroups)
EditorGUI.showMixedValue = true;
UnityEngine.GUI.SetNextControlName(s_GroupsDropdownControlName);
float iconHeight = EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing * 3;
Vector2 iconSize = EditorGUIUtility.GetIconSize();
EditorGUIUtility.SetIconSize(new Vector2(iconHeight, iconHeight));
if (s_FolderTexture == null)
{
s_FolderTexture = EditorGUIUtility.IconContent("Folder Icon").image;
}
GUIContent groupGUIContent = new GUIContent(displayGroup.Name, s_FolderTexture);
Rect groupFieldRect = GUILayoutUtility.GetRect(groupGUIContent, EditorStyles.objectField);
EditorGUI.DropdownButton(groupFieldRect, groupGUIContent, FocusType.Keyboard, EditorStyles.objectField);
EditorGUIUtility.SetIconSize(new Vector2(iconSize.x, iconSize.y));
if (mixedGroups)
EditorGUI.showMixedValue = false;
float pickerWidth = 12f;
Rect groupFieldRectNoPicker = new Rect(groupFieldRect);
groupFieldRectNoPicker.xMax = groupFieldRect.xMax - pickerWidth * 1.33f;
Rect pickerRect = new Rect(groupFieldRectNoPicker.xMax, groupFieldRectNoPicker.y, pickerWidth, groupFieldRectNoPicker.height);
bool isPickerPressed = Event.current.clickCount == 1 && pickerRect.Contains(Event.current.mousePosition);
DrawCaret(pickerRect);
if (canEditGroup)
{
bool isEnterKeyPressed = Event.current.type == EventType.KeyDown && Event.current.isKey && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return);
bool enterKeyRequestsPopup = isEnterKeyPressed && (s_GroupsDropdownControlName == UnityEngine.GUI.GetNameOfFocusedControl());
if (isPickerPressed || enterKeyRequestsPopup)
{
EditorWindow.GetWindow<GroupsPopupWindow>(true, "Select Addressable Group").Initialize(settings, entries, !mixedGroups, true, Event.current.mousePosition, AddressableAssetUtility.MoveEntriesToGroup);
}
bool isDragging = Event.current.type == EventType.DragUpdated && groupFieldRectNoPicker.Contains(Event.current.mousePosition);
bool isDropping = Event.current.type == EventType.DragPerform && groupFieldRectNoPicker.Contains(Event.current.mousePosition);
HandleDragAndDrop(settings, entries, isDragging, isDropping);
}
if (!mixedGroups)
{
if (Event.current.clickCount == 1 && groupFieldRectNoPicker.Contains(Event.current.mousePosition))
{
UnityEngine.GUI.FocusControl(s_GroupsDropdownControlName);
AddressableAssetsWindow.Init();
var window = EditorWindow.GetWindow<AddressableAssetsWindow>();
window.SelectGroupInGroupEditor(displayGroup, false);
}
if (Event.current.clickCount == 2 && groupFieldRectNoPicker.Contains(Event.current.mousePosition))
{
AddressableAssetsWindow.Init();
var window = EditorWindow.GetWindow<AddressableAssetsWindow>();
window.SelectGroupInGroupEditor(displayGroup, true);
}
}
}
}
static void DrawCaret(Rect pickerRect)
{
if (s_GroupsCaretTexture == null)
{
s_GroupsCaretTexture = EditorGUIUtility.IconContent("d_pick").image;
}
UnityEngine.GUI.DrawTexture(pickerRect, s_GroupsCaretTexture, ScaleMode.ScaleToFit);
}
static void HandleDragAndDrop(AddressableAssetSettings settings, List<AddressableAssetEntry> aaEntries, bool isDragging, bool isDropping)
{
var groupItems = DragAndDrop.GetGenericData("AssetEntryTreeViewItem") as List<AssetEntryTreeViewItem>;
if (isDragging)
{
bool canDragGroup = groupItems != null && groupItems.Count == 1 && groupItems[0].IsGroup && !groupItems[0].group.ReadOnly;
DragAndDrop.visualMode = canDragGroup ? DragAndDropVisualMode.Copy : DragAndDropVisualMode.Rejected;
}
else if (isDropping)
{
if (groupItems != null)
{
var group = groupItems[0].group;
AddressableAssetUtility.MoveEntriesToGroup(settings, aaEntries, group);
}
}
}
internal class TargetInfo
{
public UnityEngine.Object TargetObject;
public string Guid;
public string Path;
public bool IsMainAsset;
public AddressableAssetEntry MainAssetEntry;
public string Address
{
get
{
if (MainAssetEntry == null)
throw new NullReferenceException("No Entry set for Target info with AssetPath " + Path);
return MainAssetEntry.address;
}
}
}
}
}