Firstborn/Library/PackageCache/com.unity.addressables@1.19.19/Editor/Settings/AddressableAssetEntry.cs

1035 lines
43 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEditor.Build.Content;
using UnityEngine;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;
using UnityEngine.Serialization;
using UnityEngine.U2D;
namespace UnityEditor.AddressableAssets.Settings
{
interface IReferenceEntryData
{
string AssetPath { get; }
string address { get; set; }
bool IsInResources { get; set; }
HashSet<string> labels { get; }
}
internal struct ImplicitAssetEntry : IReferenceEntryData
{
public string AssetPath { get; set; }
public string address { get; set; }
public bool IsInResources { get; set; }
public HashSet<string> labels { get; set;}
}
/// <summary>
/// Contains data for an addressable asset entry.
/// </summary>
[Serializable]
public class AddressableAssetEntry : ISerializationCallbackReceiver, IReferenceEntryData
{
#pragma warning disable 0618
static Type typeof_AddressableAssetEntryCollection = typeof(AddressableAssetEntryCollection);
#pragma warning restore 0618
internal const string EditorSceneListName = "EditorSceneList";
internal const string EditorSceneListPath = "Scenes In Build";
internal const string ResourcesName = "Resources";
internal const string ResourcesPath = "*/Resources/";
[FormerlySerializedAs("m_guid")]
[SerializeField]
string m_GUID;
[FormerlySerializedAs("m_address")]
[SerializeField]
string m_Address;
[FormerlySerializedAs("m_readOnly")]
[SerializeField]
bool m_ReadOnly;
[FormerlySerializedAs("m_serializedLabels")]
[SerializeField]
List<string> m_SerializedLabels;
HashSet<string> m_Labels = new HashSet<string>();
internal virtual bool HasSettings() { return false; }
/// <summary>
/// Flag indicating if an AssetEntry is a folder or not.
/// </summary>
public bool IsFolder { get; set; }
/// <summary>
/// List of AddressableAssetEntries that are considered sub-assets of a main Asset. Typically used for Folder entires.
/// </summary>
[NonSerialized]
public List<AddressableAssetEntry> SubAssets = new List<AddressableAssetEntry>();
[NonSerialized]
AddressableAssetGroup m_ParentGroup;
/// <summary>
/// The asset group that this entry belongs to. An entry can only belong to a single group at a time.
/// </summary>
public AddressableAssetGroup parentGroup
{
get { return m_ParentGroup; }
set { m_ParentGroup = value; }
}
/// <summary>
/// The id for the bundle file.
/// </summary>
public string BundleFileId
{
get;
set;
}
/// <summary>
/// The asset guid.
/// </summary>
public string guid { get { return m_GUID; } }
/// <summary>
/// The address of the entry. This is treated as the primary key in the ResourceManager system.
/// </summary>
public string address
{
get
{
return m_Address;
}
set
{
SetAddress(value);
}
}
/// <summary>
/// Set the address of the entry.
/// </summary>
/// <param name="addr">The address.</param>
/// <param name="postEvent">Post modification event.</param>
public void SetAddress(string addr, bool postEvent = true)
{
if (m_Address != addr)
{
m_Address = addr;
if (string.IsNullOrEmpty(m_Address))
m_Address = AssetPath;
if (m_GUID.Length > 0 && m_Address.Contains("[") && m_Address.Contains("]"))
Debug.LogErrorFormat("Address '{0}' cannot contain '[ ]'.", m_Address);
SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, this, postEvent);
}
}
/// <summary>
/// Read only state of the entry.
/// </summary>
public bool ReadOnly
{
get
{
return m_ReadOnly;
}
set
{
if (m_ReadOnly != value)
{
m_ReadOnly = value;
SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, this, true);
}
}
}
/// <summary>
/// Is the asset in a resource folder.
/// </summary>
public bool IsInResources { get; set; }
/// <summary>
/// Is scene in scene list.
/// </summary>
public bool IsInSceneList { get; set; }
/// <summary>
/// Is a sub asset. For example an asset in an addressable folder.
/// </summary>
public bool IsSubAsset { get; set; }
/// <summary>
/// Stores a reference to the parent entry. Only used if the asset is a sub asset.
/// </summary>
public AddressableAssetEntry ParentEntry { get; set; }
bool m_CheckedIsScene;
bool m_IsScene;
/// <summary>
/// Is this entry for a scene.
/// </summary>
public bool IsScene
{
get
{
if (!m_CheckedIsScene)
{
m_CheckedIsScene = true;
m_IsScene = AssetPath.EndsWith(".unity");
}
return m_IsScene;
}
}
/// <summary>
/// The set of labels for this entry. There is no inherent limit to the number of labels.
/// </summary>
public HashSet<string> labels { get { return m_Labels; } }
internal Type m_cachedMainAssetType = null;
/// <summary>
/// The System.Type of the main Object referenced by an AddressableAssetEntry
/// </summary>
public Type MainAssetType
{
get
{
if (m_cachedMainAssetType == null)
{
m_cachedMainAssetType = AssetDatabase.GetMainAssetTypeAtPath(AssetPath);
if (m_cachedMainAssetType == null)
return typeof(object); // do not cache a bad type lookup.
}
return m_cachedMainAssetType;
}
}
/// <summary>
/// Set or unset a label on this entry.
/// </summary>
/// <param name="label">The label name.</param>
/// <param name="enable">Setting to true will add the label, false will remove it.</param>
/// <param name="force">When enable is true, setting force to true will force the label to exist on the parent AddressableAssetSettings object if it does not already.</param>
/// <param name="postEvent">Post modification event.</param>
/// <returns></returns>
public bool SetLabel(string label, bool enable, bool force = false, bool postEvent = true)
{
if (enable)
{
if (force)
parentGroup.Settings.AddLabel(label, postEvent);
if (m_Labels.Add(label))
{
SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, this, postEvent);
return true;
}
}
else
{
if (m_Labels.Remove(label))
{
SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, this, postEvent);
return true;
}
}
return false;
}
/// <summary>
/// Creates a list of keys that can be used to load this entry.
/// </summary>
/// <returns>The list of keys. This will contain the address, the guid as a Hash128 if valid, all assigned labels, and the scene index if applicable.</returns>
public List<object> CreateKeyList() => CreateKeyList(true, true, true);
/// <summary>
/// Creates a list of keys that can be used to load this entry.
/// </summary>
/// <returns>The list of keys. This will contain the address, the guid as a Hash128 if valid, all assigned labels, and the scene index if applicable.</returns>
internal List<object> CreateKeyList(bool includeAddress, bool includeGUID, bool includeLabels)
{
var keys = new List<object>();
//the address must be the first key
if (includeAddress)
keys.Add(address);
if (includeGUID && !string.IsNullOrEmpty(guid))
keys.Add(guid);
if (IsScene && IsInSceneList)
{
int index = BuiltinSceneCache.GetSceneIndex(new GUID(guid));
if (index != -1)
keys.Add(index);
}
if (includeLabels && labels != null && labels.Count > 0)
{
var labelsToRemove = new HashSet<string>();
var currentLabels = parentGroup.Settings.GetLabels();
foreach (var l in labels)
{
if (currentLabels.Contains(l))
keys.Add(l);
else
labelsToRemove.Add(l);
}
foreach (var l in labelsToRemove)
labels.Remove(l);
}
return keys;
}
internal AddressableAssetEntry(string guid, string address, AddressableAssetGroup parent, bool readOnly)
{
if (guid.Length > 0 && address.Contains("[") && address.Contains("]"))
Debug.LogErrorFormat("Address '{0}' cannot contain '[ ]'.", address);
m_GUID = guid;
m_Address = address;
m_ReadOnly = readOnly;
parentGroup = parent;
IsInResources = false;
IsInSceneList = false;
}
internal void SerializeForHash(BinaryFormatter formatter, Stream stream)
{
formatter.Serialize(stream, m_GUID);
formatter.Serialize(stream, m_Address);
formatter.Serialize(stream, m_ReadOnly);
formatter.Serialize(stream, m_Labels.Count);
foreach (var t in m_Labels)
formatter.Serialize(stream, t);
formatter.Serialize(stream, IsInResources);
formatter.Serialize(stream, IsInSceneList);
formatter.Serialize(stream, IsSubAsset);
}
internal void SetDirty(AddressableAssetSettings.ModificationEvent e, object o, bool postEvent)
{
if (parentGroup != null)
parentGroup.SetDirty(e, o, postEvent, true);
}
internal void SetCachedPath(string newCachedPath)
{
if (newCachedPath != m_cachedAssetPath)
{
m_cachedAssetPath = newCachedPath;
m_MainAsset = null;
m_TargetAsset = null;
}
}
internal void SetSubObjectType(Type type)
{
m_cachedMainAssetType = type;
}
internal string m_cachedAssetPath = null;
/// <summary>
/// The path of the asset.
/// </summary>
public string AssetPath
{
get
{
if (string.IsNullOrEmpty(m_cachedAssetPath))
{
if (string.IsNullOrEmpty(guid))
SetCachedPath(string.Empty);
else if (guid == EditorSceneListName)
SetCachedPath(EditorSceneListPath);
else if (guid == ResourcesName)
SetCachedPath(ResourcesPath);
else
SetCachedPath(AssetDatabase.GUIDToAssetPath(guid));
}
return m_cachedAssetPath;
}
}
private UnityEngine.Object m_MainAsset;
/// <summary>
/// The main asset object for this entry.
/// </summary>
public UnityEngine.Object MainAsset
{
get
{
if (m_MainAsset == null || !AssetDatabase.TryGetGUIDAndLocalFileIdentifier(m_MainAsset, out string guid, out long localId))
{
AddressableAssetEntry e = this;
while (string.IsNullOrEmpty(e.AssetPath))
{
if (e.ParentEntry == null)
return null;
e = e.ParentEntry;
}
m_MainAsset = AssetDatabase.LoadMainAssetAtPath(e.AssetPath);
}
return m_MainAsset;
}
}
private UnityEngine.Object m_TargetAsset;
/// <summary>
/// The asset object for this entry.
/// </summary>
public UnityEngine.Object TargetAsset
{
get
{
if (m_TargetAsset == null || !AssetDatabase.TryGetGUIDAndLocalFileIdentifier(m_TargetAsset, out string guid, out long localId))
{
if (!string.IsNullOrEmpty(AssetPath) || !IsSubAsset)
{
m_TargetAsset = MainAsset;
return m_TargetAsset;
}
if (ParentEntry == null || !string.IsNullOrEmpty(AssetPath) || string.IsNullOrEmpty(ParentEntry.AssetPath))
return null;
var mainAsset = ParentEntry.MainAsset;
if (ResourceManagerConfig.ExtractKeyAndSubKey(address, out string mainKey, out string subObjectName))
{
if (mainAsset != null && mainAsset.GetType() == typeof(SpriteAtlas))
{
m_TargetAsset = (mainAsset as SpriteAtlas).GetSprite(subObjectName);
return m_TargetAsset;
}
var subObjects = AssetDatabase.LoadAllAssetRepresentationsAtPath(ParentEntry.AssetPath);
foreach (var s in subObjects)
{
if (s != null && s.name == subObjectName)
{
m_TargetAsset = s;
break;
}
}
}
}
return m_TargetAsset;
}
}
/// <summary>
/// The asset load path. This is used to determine the internal id of resource locations.
/// </summary>
/// <param name="isBundled">True if the asset will be contained in an asset bundle.</param>
/// <returns>Return the runtime path that should be used to load this entry.</returns>
public string GetAssetLoadPath(bool isBundled)
{
return GetAssetLoadPath(isBundled, null);
}
/// <summary>
/// The asset load path. This is used to determine the internal id of resource locations.
/// </summary>
/// <param name="isBundled">True if the asset will be contained in an asset bundle.</param>
/// <param name="otherLoadPaths">The internal ids of the asset, typically shortened versions of the asset's GUID.</param>
/// <returns>Return the runtime path that should be used to load this entry.</returns>
public string GetAssetLoadPath(bool isBundled, HashSet<string> otherLoadPaths)
{
if (!IsScene)
{
if (IsInResources)
{
return GetResourcesPath(AssetPath);
}
else
{
if (isBundled)
return parentGroup.GetSchema<GroupSchemas.BundledAssetGroupSchema>().GetAssetLoadPath(AssetPath, otherLoadPaths, p => guid);
return AssetPath;
}
}
else
{
if (isBundled)
return parentGroup.GetSchema<GroupSchemas.BundledAssetGroupSchema>().GetAssetLoadPath(AssetPath, otherLoadPaths, p => guid);
var path = AssetPath;
int i = path.LastIndexOf(".unity");
if (i > 0)
path = path.Substring(0, i);
i = path.ToLower().IndexOf("assets/");
if (i == 0)
path = path.Substring("assets/".Length);
return path;
}
}
static string GetResourcesPath(string path)
{
path = path.Replace('\\', '/');
int ri = path.ToLower().LastIndexOf("/resources/");
if (ri >= 0)
path = path.Substring(ri + "/resources/".Length);
int i = path.LastIndexOf('.');
if (i > 0)
path = path.Substring(0, i);
return path;
}
/// <summary>
/// Gathers all asset entries. Each explicit entry may contain multiple sub entries. For example, addressable folders create entries for each asset contained within.
/// </summary>
/// <param name="assets">The generated list of entries. For simple entries, this will contain just the entry itself if specified.</param>
/// <param name="includeSelf">Determines if the entry should be contained in the result list or just sub entries.</param>
/// <param name="recurseAll">Determines if full recursion should be done when gathering entries.</param>
/// <param name="includeSubObjects">Determines if sub objects such as sprites should be included.</param>
/// <param name="entryFilter">Optional predicate to run against each entry, only returning those that pass. A null filter will return all entries</param>
public void GatherAllAssets(List<AddressableAssetEntry> assets, bool includeSelf, bool recurseAll, bool includeSubObjects, Func<AddressableAssetEntry, bool> entryFilter = null)
{
if (assets == null)
assets = new List<AddressableAssetEntry>();
if (guid == EditorSceneListName)
{
GatherEditorSceneEntries(assets, entryFilter);
}
else if (guid == ResourcesName)
{
GatherResourcesEntries(assets, recurseAll, entryFilter);
}
else
{
if (string.IsNullOrEmpty(AssetPath))
return;
if (AssetDatabase.IsValidFolder(AssetPath))
{
IsFolder = true;
List<AddressableAssetEntry> folderEntries = new List<AddressableAssetEntry>();
GatherFolderEntries(folderEntries, recurseAll, includeSubObjects, entryFilter);
SubAssets = folderEntries;
assets.AddRange(folderEntries);
}
else
{
#pragma warning disable 0618
bool isEntryCollection = MainAssetType == typeof_AddressableAssetEntryCollection;
#pragma warning restore 0618
if (isEntryCollection)
{
GatherAssetEntryCollectionEntries(assets, entryFilter);
}
else
{
if (includeSelf)
if (entryFilter == null || entryFilter(this))
assets.Add(this);
if (includeSubObjects)
{
var mainType = AssetDatabase.GetMainAssetTypeAtPath(AssetPath);
if (mainType == typeof(SpriteAtlas))
GatherSpriteAtlasEntries(assets);
else
GatherSubObjectEntries(assets);
}
}
}
}
}
void GatherSubObjectEntries(List<AddressableAssetEntry> assets)
{
var objs = AssetDatabase.LoadAllAssetRepresentationsAtPath(AssetPath);
for (int i = 0; i < objs.Length; i++)
{
var o = objs[i];
var namedAddress = string.Format("{0}[{1}]", address, o == null ? "missing reference" : o.name);
if (o == null)
{
Debug.LogWarning(string.Format("NullReference in entry {0}\nAssetPath: {1}\nAddressableAssetGroup: {2}", address, AssetPath, parentGroup.Name));
assets.Add(new AddressableAssetEntry("", namedAddress, parentGroup, true));
}
else
{
var newEntry = parentGroup.Settings.CreateEntry("", namedAddress, parentGroup, true);
newEntry.IsSubAsset = true;
newEntry.ParentEntry = this;
newEntry.IsInResources = IsInResources;
newEntry.SetSubObjectType(o.GetType());
assets.Add(newEntry);
}
}
}
void GatherSpriteAtlasEntries(List<AddressableAssetEntry> assets)
{
var settings = parentGroup.Settings;
var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(AssetPath);
var sprites = new Sprite[atlas.spriteCount];
atlas.GetSprites(sprites);
for (int i = 0; i < atlas.spriteCount; i++)
{
var spriteName = sprites[i] == null ? "missing reference" : sprites[i].name;
if (sprites[i] == null)
{
Debug.LogWarning(string.Format("NullReference in entry {0}\nAssetPath: {1}\nAddressableAssetGroup: {2}", address, AssetPath, parentGroup.Name));
assets.Add(new AddressableAssetEntry("", spriteName, parentGroup, true));
}
else
{
if (spriteName.EndsWith("(Clone)"))
spriteName = spriteName.Replace("(Clone)", "");
var namedAddress = string.Format("{0}[{1}]", address, spriteName);
var newEntry = settings.CreateEntry("", namedAddress, parentGroup, true);
newEntry.IsSubAsset = true;
newEntry.ParentEntry = this;
newEntry.IsInResources = IsInResources;
assets.Add(newEntry);
}
}
}
#pragma warning disable 0618
void GatherAssetEntryCollectionEntries(List<AddressableAssetEntry> assets, Func<AddressableAssetEntry, bool> entryFilter)
{
var settings = parentGroup.Settings;
var col = AssetDatabase.LoadAssetAtPath<AddressableAssetEntryCollection>(AssetPath);
if (col != null)
{
foreach (var e in col.Entries)
{
var entry = settings.CreateSubEntryIfUnique(e.guid, e.address, this);
if (entry != null)
{
entry.IsInResources = e.IsInResources;
foreach (var l in e.labels)
entry.SetLabel(l, true, false, false);
foreach (var l in m_Labels)
entry.SetLabel(l, true, false, false);
if (entryFilter == null || entryFilter(entry))
assets.Add(entry);
}
}
}
}
#pragma warning restore 0618
internal void GatherFolderEntries(List<AddressableAssetEntry> assets, bool recurseAll, bool includeSubObjects, Func<AddressableAssetEntry, bool> entryFilter)
{
var path = AssetPath;
var settings = parentGroup.Settings;
foreach (var file in AddressablesFileEnumeration.EnumerateAddressableFolder(path, settings, recurseAll))
{
var subGuid = AssetDatabase.AssetPathToGUID(file);
var entry = settings.CreateSubEntryIfUnique(subGuid, address + GetRelativePath(file, path), this);
if (entry != null)
{
entry.IsInResources =
IsInResources; //if this is a sub-folder of Resources, copy it on down
entry.m_Labels = m_Labels;
if (entryFilter == null || entryFilter(entry))
assets.Add(entry);
if (includeSubObjects)
{
var mainType = AssetDatabase.GetMainAssetTypeAtPath(entry.AssetPath);
if (mainType == typeof(SpriteAtlas))
entry.GatherSpriteAtlasEntries(assets);
else
entry.GatherSubObjectEntries(assets);
}
}
}
if (!recurseAll)
{
foreach (var fo in Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly))
{
var folder = fo.Replace('\\', '/');
if (AssetDatabase.IsValidFolder(folder))
{
var entry = settings.CreateSubEntryIfUnique(AssetDatabase.AssetPathToGUID(folder), address + GetRelativePath(folder, path), this);
if (entry != null)
{
entry.IsInResources = IsInResources; //if this is a sub-folder of Resources, copy it on down
entry.m_Labels = m_Labels;
entry.IsFolder = true;
if (entryFilter == null || entryFilter(entry))
assets.Add(entry);
}
}
}
}
}
/// <summary>
/// Gets an entry for this folder entry
/// </summary>
/// <param name="subAssetGuid"></param>
/// <param name="subAssetPath"></param>
/// <returns></returns>
/// <remarks>Assumes that this asset entry is a valid folder asset</remarks>
internal AddressableAssetEntry GetFolderSubEntry(string subAssetGuid, string subAssetPath)
{
string assetPath = AssetPath;
if (string.IsNullOrEmpty(assetPath) || !subAssetPath.StartsWith(assetPath))
return null;
var settings = parentGroup.Settings;
AddressableAssetEntry assetEntry = settings.FindAssetEntry(subAssetGuid);
if (assetEntry != null)
{
if (assetEntry.IsSubAsset && assetEntry.ParentEntry == this)
return assetEntry;
return null;
}
string relativePath = subAssetPath.Remove(0, assetPath.Length + 1);
string[] splitRelativePath = relativePath.Split('/');
string folderPath = assetPath;
for (int i = 0; i < splitRelativePath.Length - 1; ++i)
{
folderPath = folderPath + "/" + splitRelativePath[i];
string folderGuid = AssetDatabase.AssetPathToGUID(folderPath);
if (!AddressableAssetUtility.IsPathValidForEntry(folderPath))
return null;
var folderEntry = settings.CreateSubEntryIfUnique(folderGuid, address + "/" + folderPath.Remove(assetPath.Length), this);
if (folderEntry != null)
{
folderEntry.IsInResources = IsInResources;
folderEntry.m_Labels = m_Labels;
folderEntry.IsFolder = true;
}
else
return null;
}
assetEntry = settings.CreateSubEntryIfUnique(subAssetGuid, address + relativePath, this);
if (assetEntry == null || assetEntry.IsSubAsset == false)
return null;
return assetEntry;
}
#pragma warning disable 0618
internal AddressableAssetEntry GetAssetCollectionSubEntry(string subAssetGuid)
{
if (AssetPath.EndsWith(".asset") && MainAssetType == typeof_AddressableAssetEntryCollection)
{
List<AddressableAssetEntry> implicitEntries = new List<AddressableAssetEntry>();
GatherAssetEntryCollectionEntries(implicitEntries, null);
return implicitEntries.FirstOrDefault(ie => ie.guid == subAssetGuid);
}
return null;
}
#pragma warning restore 0618
internal void GatherResourcesEntries(List<AddressableAssetEntry> assets, bool recurseAll, Func<AddressableAssetEntry, bool> entryFilter)
{
var settings = parentGroup.Settings;
var pd = parentGroup.GetSchema<GroupSchemas.PlayerDataGroupSchema>();
if (pd.IncludeResourcesFolders)
{
foreach (var resourcesDir in GetResourceDirectories())
{
foreach (var file in Directory.GetFiles(resourcesDir, "*.*", recurseAll ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
{
if (AddressableAssetUtility.IsPathValidForEntry(file))
{
var g = AssetDatabase.AssetPathToGUID(file);
var addr = GetResourcesPath(file);
var entry = settings.CreateSubEntryIfUnique(g, addr, this);
if (entry != null) //TODO - it's probably really bad if this is ever null. need some error detection
{
entry.IsInResources = true;
entry.m_Labels = m_Labels;
if (entryFilter == null || entryFilter(entry))
assets.Add(entry);
}
}
}
if (!recurseAll)
{
foreach (var folder in Directory.GetDirectories(resourcesDir))
{
if (AssetDatabase.IsValidFolder(folder))
{
var entry = settings.CreateSubEntryIfUnique(AssetDatabase.AssetPathToGUID(folder), GetResourcesPath(folder), this);
if (entry != null) //TODO - it's probably really bad if this is ever null. need some error detection
{
entry.IsInResources = true;
entry.m_Labels = m_Labels;
if (entryFilter == null || entryFilter(entry))
assets.Add(entry);
}
}
}
}
}
}
}
static IEnumerable<string> GetResourceDirectories()
{
string[] resourcesGuids = AssetDatabase.FindAssets("Resources", new string[] { "Assets", "Packages" });
foreach (string resourcesGuid in resourcesGuids)
{
string resourcesAssetPath = AssetDatabase.GUIDToAssetPath(resourcesGuid);
if (resourcesAssetPath.EndsWith("/resources", StringComparison.OrdinalIgnoreCase) && AssetDatabase.IsValidFolder(resourcesAssetPath) && Directory.Exists(resourcesAssetPath))
{
yield return resourcesAssetPath;
}
}
}
void GatherEditorSceneEntries(List<AddressableAssetEntry> assets, Func<AddressableAssetEntry, bool> entryFilter)
{
var settings = parentGroup.Settings;
var pd = parentGroup.GetSchema<GroupSchemas.PlayerDataGroupSchema>();
if (pd.IncludeBuildSettingsScenes)
{
foreach (var s in BuiltinSceneCache.scenes)
{
if (s.enabled)
{
var entry = settings.CreateSubEntryIfUnique(s.guid.ToString(), Path.GetFileNameWithoutExtension(s.path), this);
if (entry != null) //TODO - it's probably really bad if this is ever null. need some error detection
{
entry.IsInSceneList = true;
entry.m_Labels = m_Labels;
if (entryFilter == null || entryFilter(entry))
assets.Add(entry);
}
}
}
}
}
internal void GatherAllAssetReferenceDrawableEntries(List<IReferenceEntryData> refEntries, AddressableAssetSettings settings)
{
var path = AssetPath;
if (string.IsNullOrEmpty(path))
return;
if (guid == EditorSceneListName)
{
//We don't add Built in scenes to the list of assignable AssetReferences so no need to check this.
return;
}
if (guid == ResourcesName)
{
//We don't add Resources assets to the list of assignable AssetReferences so no need to check this.
return;
}
if (AssetDatabase.IsValidFolder(path))
{
foreach (var fi in AddressablesFileEnumeration.EnumerateAddressableFolder(path, settings, true))
{
string relativeAddress = address + GetRelativePath(fi, path);
var reference = new ImplicitAssetEntry()
{
address = relativeAddress,
AssetPath = fi,
IsInResources = IsInResources,
labels = new HashSet<string>(m_Labels)
};
refEntries.Add(reference);
}
}
#pragma warning disable 0618
else if (MainAssetType == typeof_AddressableAssetEntryCollection)
{
var col = AssetDatabase.LoadAssetAtPath<AddressableAssetEntryCollection>(AssetPath);
if (col != null)
{
foreach (var e in col.Entries)
{
refEntries.Add(new ImplicitAssetEntry()
{
address = e.address,
AssetPath = e.AssetPath,
IsInResources = e.IsInResources,
labels = new HashSet<string>(e.labels.Union(this.labels))
});
}
}
}
#pragma warning restore 0618
else
{
refEntries.Add(this);
}
}
internal AddressableAssetEntry GetImplicitEntry(string implicitAssetGuid, string implicitAssetPath)
{
var e = GetAssetCollectionSubEntry(implicitAssetGuid);
return e != null ? e : GetFolderSubEntry(implicitAssetGuid, implicitAssetPath);
}
string GetRelativePath(string file, string path)
{
return file.Substring(path.Length);
}
/// <summary>
/// Implementation of ISerializationCallbackReceiver. Converts data to serializable form before serialization.
/// </summary>
public void OnBeforeSerialize()
{
m_SerializedLabels = new List<string>();
foreach (var t in m_Labels)
m_SerializedLabels.Add(t);
}
/// <summary>
/// Implementation of ISerializationCallbackReceiver. Converts data from serializable form after deserialization.
/// </summary>
public void OnAfterDeserialize()
{
m_Labels = new HashSet<string>();
foreach (var s in m_SerializedLabels)
m_Labels.Add(s);
m_SerializedLabels = null;
m_cachedMainAssetType = null;
m_cachedAssetPath = null;
m_CheckedIsScene = false;
m_MainAsset = null;
m_TargetAsset = null;
SubAssets?.Clear();
}
/// <summary>
/// Returns the address of the AddressableAssetEntry.
/// </summary>
/// <returns>The address of the AddressableAssetEntry</returns>
public override string ToString()
{
return m_Address;
}
/// <summary>
/// Create all entries for this addressable asset. This will expand subassets (Sprites, Meshes, etc) and also different representations.
/// </summary>
/// <param name="entries">The list of entries to fill in.</param>
/// <param name="isBundled">Whether the entry is bundles or not. This will affect the load path.</param>
/// <param name="providerType">The provider type for the main entry.</param>
/// <param name="dependencies">Keys of dependencies</param>
/// <param name="extraData">Extra data to append to catalog entries.</param>
/// <param name="providerTypes">Any unknown provider types are added to this set in order to ensure they are not stripped.</param>
public void CreateCatalogEntries(List<ContentCatalogDataEntry> entries, bool isBundled, string providerType, IEnumerable<object> dependencies, object extraData, HashSet<Type> providerTypes)
{
CreateCatalogEntries(entries, isBundled, providerType, dependencies, extraData, null, providerTypes, true, true, true, null);
}
/// <summary>
/// Create all entries for this addressable asset. This will expand subassets (Sprites, Meshes, etc) and also different representations.
/// </summary>
/// <param name="entries">The list of entries to fill in.</param>
/// <param name="isBundled">Whether the entry is bundles or not. This will affect the load path.</param>
/// <param name="providerType">The provider type for the main entry.</param>
/// <param name="dependencies">Keys of dependencies</param>
/// <param name="extraData">Extra data to append to catalog entries.</param>
/// <param name="depInfo">Map of guids to AssetLoadInfo for object identifiers in an Asset. If null, ContentBuildInterface gathers object ids automatically.</param>
/// <param name="providerTypes">Any unknown provider types are added to this set in order to ensure they are not stripped.</param>
/// <param name="includeAddress">Flag indicating if address locations should be included</param>
/// <param name="includeGUID">Flag indicating if guid locations should be included</param>
/// <param name="includeLabels">Flag indicating if label locations should be included</param>
/// <param name="assetsInBundle">The internal ids of the asset, typically shortened versions of the asset's GUID.</param>
public void CreateCatalogEntries(List<ContentCatalogDataEntry> entries, bool isBundled, string providerType, IEnumerable<object> dependencies, object extraData, Dictionary<GUID, AssetLoadInfo> depInfo, HashSet<Type> providerTypes, bool includeAddress, bool includeGUID, bool includeLabels, HashSet<string> assetsInBundle)
{
if (string.IsNullOrEmpty(AssetPath))
return;
string assetPath = GetAssetLoadPath(isBundled, assetsInBundle);
List<object> keyList = CreateKeyList(includeAddress, includeGUID, includeLabels);
if (keyList.Count == 0)
return;
//The asset may have previously been invalid. Since then, it may have been re-imported.
//This can occur in particular when using ScriptedImporters with complex, multi-step behavior.
//Double-check the type here in case the asset has been imported correctly after we cached its type.
if (MainAssetType == typeof(DefaultAsset))
m_cachedMainAssetType = null;
Type mainType = AddressableAssetUtility.MapEditorTypeToRuntimeType(MainAssetType, false);
if ((mainType == null || mainType == typeof(DefaultAsset)) && !IsInResources)
{
var t = MainAssetType;
Debug.LogWarningFormat("Type {0} is in editor assembly {1}. Asset location with internal id {2} will be stripped.", t.Name, t.Assembly.FullName, assetPath);
return;
}
Type runtimeProvider = GetRuntimeProviderType(providerType, mainType);
if (runtimeProvider != null)
providerTypes.Add(runtimeProvider);
if (!IsScene)
{
ObjectIdentifier[] ids = depInfo != null ? depInfo[new GUID(guid)].includedObjects.ToArray() :
ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(new GUID(guid), EditorUserBuildSettings.activeBuildTarget);
foreach (var t in GatherMainAndReferencedSerializedTypes(ids))
entries.Add(new ContentCatalogDataEntry(t, assetPath, providerType, keyList, dependencies, extraData));
}
else if (mainType != null && mainType != typeof(DefaultAsset))
{
entries.Add(new ContentCatalogDataEntry(mainType, assetPath, providerType, keyList, dependencies, extraData));
}
}
static internal IEnumerable<Type> GatherMainAndReferencedSerializedTypes(ObjectIdentifier[] ids)
{
if (ids.Length > 0)
{
Type[] typesForObjs = ContentBuildInterface.GetTypeForObjects(ids);
HashSet<Type> typesSeen = new HashSet<Type>();
foreach (var objType in typesForObjs)
{
if (typeof(Component).IsAssignableFrom(objType))
continue;
Type rtType = AddressableAssetUtility.MapEditorTypeToRuntimeType(objType, false);
if (rtType != null && rtType != typeof(DefaultAsset) && !typesSeen.Contains(rtType))
{
yield return rtType;
typesSeen.Add(rtType);
}
}
}
}
static internal List<Type> GatherMainObjectTypes(ObjectIdentifier[] ids)
{
List<Type> typesSeen = new List<Type>();
foreach (ObjectIdentifier id in ids)
{
Type objType = ContentBuildInterface.GetTypeForObject(id);
if (typeof(Component).IsAssignableFrom(objType))
continue;
Type rtType = AddressableAssetUtility.MapEditorTypeToRuntimeType(objType, false);
if (rtType != null && rtType != typeof(DefaultAsset) && !typesSeen.Contains(rtType))
typesSeen.Add(rtType);
}
return typesSeen;
}
internal Type GetRuntimeProviderType(string providerType, Type mainEntryType)
{
if (string.IsNullOrEmpty(providerType))
return null;
if (mainEntryType == typeof(SpriteAtlas))
return typeof(AtlasSpriteProvider);
return Assembly.GetAssembly(typeof(ResourceProviderBase)).GetType(providerType);
}
}
}