using System.Collections.Generic; using System.IO; using UnityEditor.AssetImporters; using UnityEngine; using UnityEngine.U2D.Animation; namespace UnityEditor.U2D.Animation { /// /// A ScriptedImporter that imports .spriteLib extension file to generate /// SpriteLibraryAsset /// [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@9.0/manual/SL-Asset.html")] [ScriptedImporter(22100000, "spriteLib", AllowCaching = true)] public class SpriteLibrarySourceAssetImporter : ScriptedImporter { /// /// Implementation of ScriptedImporter.OnImportAsset /// /// /// This argument contains all the contextual information needed to process the import /// event and is also used by the custom importer to store the resulting Unity Asset. /// public override void OnImportAsset(AssetImportContext ctx) { var spriteLib = ScriptableObject.CreateInstance(); spriteLib.name = Path.GetFileNameWithoutExtension(assetPath); var sourceAsset = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(assetPath); if (sourceAsset?.Length > 0) { var sourceLibraryAsset = sourceAsset[0] as SpriteLibrarySourceAsset; if (sourceLibraryAsset != null) { if (!HasValidMainLibrary(sourceLibraryAsset, assetPath)) sourceLibraryAsset.SetPrimaryLibraryGUID(string.Empty); UpdateSpriteLibrarySourceAssetLibraryWithMainAsset(sourceLibraryAsset); foreach (var cat in sourceLibraryAsset.library) { spriteLib.AddCategoryLabel(null, cat.name, null); foreach (var entry in cat.overrideEntries) { spriteLib.AddCategoryLabel(entry.spriteOverride, cat.name, entry.name); } } spriteLib.modificationHash = sourceLibraryAsset.modificationHash; spriteLib.version = sourceLibraryAsset.version; if (!string.IsNullOrEmpty(sourceLibraryAsset.primaryLibraryGUID)) ctx.DependsOnArtifact(AssetDatabase.GUIDToAssetPath(sourceLibraryAsset.primaryLibraryGUID)); } } ctx.AddObjectToAsset("SpriteLib", spriteLib, EditorIconUtility.LoadIconResource("Animation.SpriteLibrary", "ComponentIcons", "ComponentIcons")); } internal static void UpdateSpriteLibrarySourceAssetLibraryWithMainAsset(SpriteLibrarySourceAsset sourceLibraryAsset) { var so = new SerializedObject(sourceLibraryAsset); var library = so.FindProperty(SpriteLibrarySourceAssetPropertyString.library); var mainLibraryAssetAssetPath = AssetDatabase.GUIDToAssetPath(sourceLibraryAsset.primaryLibraryGUID); var mainLibraryAsset = AssetDatabase.LoadAssetAtPath(mainLibraryAssetAssetPath); SpriteLibraryDataInspector.UpdateLibraryWithNewMainLibrary(mainLibraryAsset, library); if (so.hasModifiedProperties) { var modHashProperty = so.FindProperty(SpriteLibrarySourceAssetPropertyString.modificationHash); modHashProperty.longValue = mainLibraryAsset != null ? mainLibraryAsset.modificationHash : SpriteLibraryUtility.GenerateHash(); so.ApplyModifiedPropertiesWithoutUndo(); } } internal static bool HasValidMainLibrary(SpriteLibrarySourceAsset sourceLibraryAsset, string assetPath) { if (string.IsNullOrEmpty(sourceLibraryAsset.primaryLibraryGUID)) return false; var primaryLibraryPath = AssetDatabase.GUIDToAssetPath(sourceLibraryAsset.primaryLibraryGUID); if (assetPath == primaryLibraryPath) return false; var primaryAssetParentChain = GetAssetParentChain(AssetDatabase.LoadAssetAtPath(primaryLibraryPath)); foreach (var parentLibrary in primaryAssetParentChain) { var parentPath = AssetDatabase.GetAssetPath(parentLibrary); if (parentPath == assetPath) return false; } return true; } internal static SpriteLibrarySourceAsset LoadSpriteLibrarySourceAsset(string path) { var loadedObjects = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(path); foreach (var obj in loadedObjects) { if (obj is SpriteLibrarySourceAsset) return (SpriteLibrarySourceAsset)obj; } return null; } internal static void SaveSpriteLibrarySourceAsset(SpriteLibrarySourceAsset obj, string path) { if (!HasValidMainLibrary(obj, path)) obj.SetPrimaryLibraryGUID(string.Empty); UnityEditorInternal.InternalEditorUtility.SaveToSerializedFileAndForget(new[] { obj }, path, true); } [MenuItem("internal:Assets/Convert to SpriteLibrarySourceAsset", true)] static bool ConvertToSpriteLibrarySourceAssetValidate() { foreach (var obj in Selection.objects) { if (obj is SpriteLibraryAsset) return true; } return false; } [MenuItem("internal:Assets/Convert to SpriteLibrarySourceAsset")] static void ConvertToSourceAsset() { foreach (var obj in Selection.objects) { if (obj is SpriteLibraryAsset) { var asset = (SpriteLibraryAsset)obj; var path = AssetDatabase.GetAssetPath(asset); var currentAssetPath = Path.GetDirectoryName(path); var fileName = Path.GetFileNameWithoutExtension(path); var convertFileName = fileName + SpriteLibrarySourceAsset.extension; convertFileName = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(currentAssetPath, convertFileName)); var convertAsset = ScriptableObject.CreateInstance(); convertAsset.SetLibrary(new List(asset.categories.Count)); for (var i = 0; i < asset.categories.Count; ++i) { var category = asset.categories[i]; var newCategory = new SpriteLibCategoryOverride() { overrideEntries = new List(category.categoryList.Count), name = category.name, entryOverrideCount = 0, fromMain = false }; convertAsset.AddCategory(newCategory); for (var j = 0; j < category.categoryList.Count; ++j) { newCategory.overrideEntries.Add(new SpriteCategoryEntryOverride() { name = category.categoryList[j].name, sprite = null, fromMain = false, spriteOverride = category.categoryList[j].sprite }); } } SaveSpriteLibrarySourceAsset(convertAsset, convertFileName); } } AssetDatabase.Refresh(); } internal static SpriteLibraryAsset GetAssetParent(SpriteLibraryAsset asset) { var currentAssetPath = AssetDatabase.GetAssetPath(asset); if (AssetImporter.GetAtPath(currentAssetPath) is SpriteLibrarySourceAssetImporter) { var sourceAsset = LoadSpriteLibrarySourceAsset(currentAssetPath); var primaryLibraryId = sourceAsset != null ? sourceAsset.primaryLibraryGUID : null; if (primaryLibraryId != null) { var primaryLibraryAssetAssetPath = AssetDatabase.GUIDToAssetPath(primaryLibraryId); return AssetDatabase.LoadAssetAtPath(primaryLibraryAssetAssetPath); } } return null; } internal static List GetAssetParentChain(SpriteLibraryAsset asset) { var chain = new List(); if (asset != null) { var parent = GetAssetParent(asset); while (parent != null && !chain.Contains(parent)) { chain.Add(parent); parent = GetAssetParent(parent); } } return chain; } internal static SpriteLibraryAsset GetAssetFromSelection() { foreach (var selectedObject in Selection.objects) { var selectedAsset = selectedObject as SpriteLibraryAsset; if (selectedAsset != null) return selectedAsset; } return null; } } }