330 lines
15 KiB
C#
330 lines
15 KiB
C#
![]() |
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.IO;
|
||
|
using System.Linq;
|
||
|
using UnityEditor.AddressableAssets.Build;
|
||
|
using UnityEditor.AddressableAssets.Settings;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace UnityEditor.AddressableAssets.GUI
|
||
|
{
|
||
|
using Object = UnityEngine.Object;
|
||
|
|
||
|
[InitializeOnLoad]
|
||
|
internal static class AddressableAssetInspectorGUI
|
||
|
{
|
||
|
static GUIStyle s_ToggleMixed;
|
||
|
static GUIContent s_AddressableAssetToggleText;
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void OnPostHeaderGUI(Editor editor)
|
||
|
{
|
||
|
var aaSettings = AddressableAssetSettingsDefaultObject.Settings;
|
||
|
|
||
|
if (editor.targets.Length > 0)
|
||
|
{
|
||
|
foreach (var t in editor.targets)
|
||
|
{
|
||
|
if (t is AddressableAssetGroup || t is AddressableAssetGroupSchema)
|
||
|
{
|
||
|
GUILayout.BeginHorizontal();
|
||
|
GUILayout.Label("Profile: " + AddressableAssetSettingsDefaultObject.GetSettings(true).profileSettings.
|
||
|
GetProfileName(AddressableAssetSettingsDefaultObject.GetSettings(true).activeProfileId));
|
||
|
|
||
|
GUILayout.FlexibleSpace();
|
||
|
if (GUILayout.Button("System Settings", "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();
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static List<TargetInfo> GatherTargetInfos(Object[] targets, AddressableAssetSettings aaSettings)
|
||
|
{
|
||
|
var targetInfos = new List<TargetInfo>();
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|