using System; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.Serialization; namespace UnityEditor.AddressableAssets.Settings { using Object = UnityEngine.Object; /// <summary> /// Collection of AddressableAssetGroupSchema objects /// </summary> [Serializable] public class AddressableAssetGroupSchemaSet { [FormerlySerializedAs("m_schemas")] [SerializeField] List<AddressableAssetGroupSchema> m_Schemas = new List<AddressableAssetGroupSchema>(); /// <summary> /// List of schemas for this group. /// </summary> public List<AddressableAssetGroupSchema> Schemas { get { return m_Schemas; } } /// <summary> /// Get the list of schema types. /// </summary> public List<Type> Types { get { var types = new List<Type>(m_Schemas.Count); foreach (var s in m_Schemas) types.Add(s.GetType()); return types; } } /// <summary> /// Adds a copy of the provided schema object. /// </summary> /// <param name="schema">The schema to copy.</param> /// <param name="pathFunc">A function that returns the path where this method can save the schema asset. Set to null to not create an in-project asset.</param> /// <returns>The created schema object.</returns> public AddressableAssetGroupSchema AddSchema(AddressableAssetGroupSchema schema, Func<Type, string> pathFunc) { if (schema == null) { Debug.LogWarning("Cannot add null Schema object."); return null; } var type = schema.GetType(); if (GetSchema(type) != null) { Debug.LogWarningFormat("Cannot add multiple schemas of the same type: {0}.", type.FullName); return null; } if (pathFunc == null) { m_Schemas.Add(schema); return schema; } var assetName = pathFunc(type); if (File.Exists(assetName)) { Debug.LogWarningFormat("Schema asset already exists at path {0}, relinking.", assetName); var existingSchema = AssetDatabase.LoadAssetAtPath(assetName, type) as AddressableAssetGroupSchema; m_Schemas.Add(existingSchema); return existingSchema; } var newSchema = Object.Instantiate(schema); if (!string.IsNullOrEmpty(assetName)) { var dir = Path.GetDirectoryName(assetName); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir); AssetDatabase.CreateAsset(newSchema, assetName); } m_Schemas.Add(newSchema); return newSchema; } /// <summary> /// Creates and adds a schema of a given type to this group. The schema asset will be created in the GroupSchemas directory relative to the settings asset. /// </summary> /// <param name="type">The schema type. This type must not already be added.</param> /// <param name="pathFunc">A function that returns the path where this method can save the schema asset. Set to null to not create an in-project asset.</param> /// <returns>The created schema object.</returns> public AddressableAssetGroupSchema AddSchema(Type type, Func<Type, string> pathFunc) { if (type == null) { Debug.LogWarning("Cannot add null Schema type."); return null; } if (!typeof(AddressableAssetGroupSchema).IsAssignableFrom(type)) { Debug.LogWarningFormat("Invalid Schema type {0}. Schemas must inherit from AddressableAssetGroupSchema.", type.FullName); return null; } var existing = GetSchema(type); if (existing != null) { Debug.LogWarningFormat("Cannot add multiple schemas of the same type: {0}.", existing.GetType().FullName); return existing; } var assetName = pathFunc(type); if (File.Exists(assetName)) { Debug.LogWarningFormat("Schema asset already exists at path {0}, relinking.", assetName); var existingSchema = AssetDatabase.LoadAssetAtPath(assetName, type) as AddressableAssetGroupSchema; m_Schemas.Add(existingSchema); return existingSchema; } var schema = ScriptableObject.CreateInstance(type) as AddressableAssetGroupSchema; if (!string.IsNullOrEmpty(assetName)) { var dir = Path.GetDirectoryName(assetName); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir); AssetDatabase.CreateAsset(schema, assetName); } m_Schemas.Add(schema); return schema; } /// <summary> /// Remove a given schema from this group. /// </summary> /// <param name="type">The schema type.</param> /// <returns>True if the schema was found and removed, false otherwise.</returns> public bool RemoveSchema(Type type) { for (int i = 0; i < m_Schemas.Count; i++) { var s = m_Schemas[i]; if (s.GetType() == type) { m_Schemas.RemoveAt(i); string guid; long lfid; if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(s, out guid, out lfid)) AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(guid)); return true; } } return false; } /// <summary> /// Gets an added schema of the specified type. /// </summary> /// <param name="type">The schema type.</param> /// <returns>The schema if found, otherwise null.</returns> public AddressableAssetGroupSchema GetSchema(Type type) { if (type == null) { Debug.LogWarning("Cannot get schema with null type."); return null; } if (!typeof(AddressableAssetGroupSchema).IsAssignableFrom(type)) { Debug.LogWarningFormat("Invalid Schema type {0}. Schemas must inherit from AddressableAssetGroupSchema.", type.FullName); return null; } foreach (var s in m_Schemas) if (type == s.GetType()) return s; return null; } /// <summary> /// Removes all schemas and optionally deletes the assets associated with them. /// </summary> /// <param name="deleteAssets">If true, the schema assets will also be deleted.</param> public void ClearSchemas(bool deleteAssets) { if (deleteAssets) { for (int i = 0; i < m_Schemas.Count; i++) { var s = m_Schemas[i]; string guid; long lfid; if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(s, out guid, out lfid)) { var path = AssetDatabase.GUIDToAssetPath(guid); if (File.Exists(path)) AssetDatabase.DeleteAsset(path); } } } m_Schemas.Clear(); } internal bool RenameSchemaAssets(Func<Type, string> pathFunc) { bool result = true; foreach (var schema in m_Schemas) { string guid; if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(schema, out guid, out long lfid)) continue; string path = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(path)) continue; string newPath = pathFunc(schema.GetType()); if (path == newPath) continue; string setPath = AssetDatabase.MoveAsset(path, newPath); if (!string.IsNullOrEmpty(setPath)) result = false; } return result; } } }