123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- using System;
- using System.IO;
- using System.Linq;
- using System.Collections.Generic;
- using System.Reflection;
- using UnityEditor.SceneManagement;
- using UnityEditor.U2D.Sprites;
- using UnityEngine;
- using UnityEngine.SceneManagement;
- using UnityEngine.U2D.Animation;
-
- using Object = UnityEngine.Object;
-
- namespace UnityEditor.U2D.Animation.Upgrading
- {
- internal class SpriteLibUpgrader : BaseUpgrader
- {
- static class Contents
- {
- public static readonly string ProgressBarTitle = L10n.Tr("Upgrading Sprite Library Assets");
- public static readonly string VerifyingSelection = L10n.Tr("Verifying the selection");
- public static readonly string CreatingNewLibraries = L10n.Tr("Creating new Sprite Library Assets");
- public static readonly string ReassignAssetsInComponents = L10n.Tr("Re-assigning assets in components");
- public static readonly string RemoveOldSpriteLibraries = L10n.Tr("Removing old Sprite Library Assets");
- }
-
- const string k_SpriteLibTypeId = "t:SpriteLibraryAsset";
- const string k_PsbImporterCategoriesId = "m_SpriteCategoryList.m_Categories";
- static readonly Dictionary<Type, List<FieldInfo>> k_SpriteLibraryReferenceLookup;
-
- bool m_OnlyFindOldAssets;
- bool m_OnlySearchInAssets;
-
- HashSet<int> m_IndicesWithAssetBundleConnection = new HashSet<int>();
- HashSet<string> m_AssetBundlesNeedingUpgrade = new HashSet<string>();
-
- static SpriteLibUpgrader()
- {
- k_SpriteLibraryReferenceLookup = GetSpriteLibReferenceLookup();
- }
-
- /// <param name="onlyFindOldAssets">Set this to true if you only want to find .asset SpriteLibraries</param>
- /// <param name="onlySearchInAssets">Set this to true if you only want to find SpriteLibraries in the Assets/ folder or its children</param>
- public SpriteLibUpgrader(bool onlyFindOldAssets = true, bool onlySearchInAssets = true)
- {
- m_OnlyFindOldAssets = onlyFindOldAssets;
- m_OnlySearchInAssets = onlySearchInAssets;
- }
-
- static Dictionary<Type, List<FieldInfo>> GetSpriteLibReferenceLookup()
- {
- var result = new Dictionary<Type, List<FieldInfo>>();
-
- var allObjectsWithSpriteLibProperties = TypeCache
- .GetTypesDerivedFrom<Component>()
- .Where(type => type
- .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
- .Any(HasSpriteLibField));
-
- foreach (var property in allObjectsWithSpriteLibProperties)
- {
- if (!result.ContainsKey(property))
- result.Add(property, new List<FieldInfo>());
-
- var libraryFields = property
- .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
- .Where(HasSpriteLibField)
- .ToList();
-
- foreach (var field in libraryFields)
- {
- result[property].Add(field);
- }
- }
-
- return result;
- }
-
- static bool HasSpriteLibField(FieldInfo field)
- {
- return (field.FieldType == typeof(SpriteLibraryAsset) ||
- field.FieldType == typeof(SpriteLibraryAsset[]) ||
- field.FieldType == typeof(List<SpriteLibraryAsset>)) &&
- (field.IsPublic || field.IsDefined(typeof(SerializeField)));
- }
-
- internal override List<Object> GetUpgradableAssets()
- {
- var rootFolder = m_OnlySearchInAssets ? new[] { "Assets" } : null;
- var assetPaths = AssetDatabase.FindAssets(k_SpriteLibTypeId, rootFolder)
- .Select(AssetDatabase.GUIDToAssetPath).ToArray();
-
- if (m_OnlyFindOldAssets)
- {
- assetPaths = assetPaths
- .Where(x => x.EndsWith(".asset") || UpgradeUtilities.IsPsbImportedFile(x))
- .ToArray();
- }
-
- var assets = assetPaths
- .Select(AssetDatabase.LoadAssetAtPath<SpriteLibraryAsset>)
- .Cast<Object>()
- .ToList();
- return assets;
- }
-
- internal override UpgradeReport UpgradeSelection(List<ObjectIndexPair> objects)
- {
- EditorUtility.DisplayProgressBar(Contents.ProgressBarTitle, Contents.VerifyingSelection, 0f);
-
- var entries = new List<UpgradeEntry>();
-
- var libraryIndexPairs = new Dictionary<int, SpriteLibraryAsset>();
- string msg;
- foreach (var obj in objects)
- {
- if (obj.Target == null)
- {
- msg = "The upgrade failed. Invalid selection.";
- m_Logger.Add(msg);
- m_Logger.AddLineBreak();
- entries.Add(new UpgradeEntry()
- {
- Result = UpgradeResult.Error,
- Target = obj.Target,
- Index = obj.Index,
- Message = msg
- });
- }
- else if (obj.Target is SpriteLibraryAsset lib)
- {
- libraryIndexPairs.Add(obj.Index, lib);
- }
- else
- {
- msg = $"The upgrade failed. {obj.Target.name} is not a SpriteLibraryAsset.";
- m_Logger.Add(msg);
- m_Logger.AddLineBreak();
- entries.Add(new UpgradeEntry()
- {
- Result = UpgradeResult.Error,
- Target = obj.Target,
- Index = obj.Index,
- Message = msg
- });
- }
- }
- var oldLibraries = libraryIndexPairs.Values.ToList();
-
- EditorUtility.DisplayProgressBar(Contents.ProgressBarTitle, Contents.CreatingNewLibraries, 0.2f);
- m_Logger.AddLineBreak();
- m_Logger.Add(Contents.CreatingNewLibraries);
- var newSourceAssetPaths = CreateNewAssetLibraries(libraryIndexPairs);
- AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
- var newLibraries = LoadNewLibraries(newSourceAssetPaths);
-
- EditorUtility.DisplayProgressBar(Contents.ProgressBarTitle, Contents.ReassignAssetsInComponents, 0.4f);
- m_Logger.AddLineBreak();
- m_Logger.Add(Contents.ReassignAssetsInComponents);
- var assetPaths = GetAllAssetPaths(libraryIndexPairs);
- if (assetPaths.Length > 0)
- ReassignAssets(assetPaths, oldLibraries, newLibraries);
-
- EditorUtility.DisplayProgressBar(Contents.ProgressBarTitle, Contents.RemoveOldSpriteLibraries, 0.8f);
- m_Logger.AddLineBreak();
- m_Logger.Add(Contents.RemoveOldSpriteLibraries);
- RemoveOldLibraries(oldLibraries);
- AssetDatabase.Refresh();
-
- for (var i = 0; i < newLibraries.Count; ++i)
- {
- UpgradeResult result;
- if (m_IndicesWithAssetBundleConnection.Contains(newSourceAssetPaths[i].Item1))
- {
- msg = $"Successfully replaced {newLibraries[i].name}. Note that the asset is connected to an AssetBundle. Make sure to rebuild this AssetBundle to complete the upgrade. See more info in the upgrade log.";
- result = UpgradeResult.Warning;
- }
- else
- {
- msg = $"Successfully replaced {newLibraries[i].name}";
- result = UpgradeResult.Successful;
- }
-
- m_Logger.Add(msg);
- entries.Add(new UpgradeEntry()
- {
- Result = result,
- Target = newLibraries[i],
- Index = newSourceAssetPaths[i].Item1,
- Message = msg
- });
- }
-
- EditorUtility.ClearProgressBar();
-
- if (m_AssetBundlesNeedingUpgrade.Count > 0)
- AddAssetBundlesToLog();
-
- var report = new UpgradeReport()
- {
- UpgradeEntries = entries,
- Log = m_Logger.GetLog()
- };
-
- m_Logger.Clear();
- m_AssetBundlesNeedingUpgrade.Clear();
- return report;
- }
-
- static string[] GetAllAssetPaths(Dictionary<int, SpriteLibraryAsset> spriteLibraries)
- {
- var ids = new List<string>();
- foreach(var lib in spriteLibraries.Values)
- ids.Add(GetObjectIDString(lib));
- var spriteLibIds = ids.ToArray();
-
- var assetPaths = new List<string>();
- var allAssetPaths = AssetDatabase.GetAllAssetPaths();
- foreach (var path in allAssetPaths)
- {
- if (!IsPrefabOrScenePath(path, spriteLibIds))
- continue;
-
- assetPaths.Add(path);
- }
-
- return assetPaths.ToArray();
- }
-
- static string GetObjectIDString(Object obj)
- {
- if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj.GetInstanceID(), out string guid, out long localId))
- return "fileID: " + localId + ", guid: " + guid;
-
- return null;
- }
-
- static bool IsPrefabOrScenePath(string path, string[] ids)
- {
- if (string.IsNullOrEmpty(path))
- throw new ArgumentNullException(nameof(path));
-
- if (path.StartsWith("Packages"))
- return false;
-
- if (path.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".unity", StringComparison.OrdinalIgnoreCase))
- return DoesFileContainString(path, ids);
-
- return false;
- }
-
- static bool DoesFileContainString(string path, string[] strings)
- {
- if (strings != null && strings.Length > 0)
- {
- using (var file = File.OpenText(path))
- {
- string line;
- while ((line = file.ReadLine()) != null)
- {
- for (var i = 0; i < strings.Length; i++)
- {
- if (line.Contains(strings[i]))
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
- List<(int, string)> CreateNewAssetLibraries(Dictionary<int, SpriteLibraryAsset> spriteLibraries)
- {
- var newLibraryPaths = new List<(int, string)>();
- foreach (var pair in spriteLibraries)
- {
- var sourceAsset = pair.Value;
-
- var path = AssetDatabase.GetAssetPath(sourceAsset);
- var currentAssetPath = Path.GetDirectoryName(path);
- var fileName = Path.GetFileNameWithoutExtension(path);
- var convertFileName = fileName + SpriteLibrarySourceAsset.extension;
- convertFileName = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(currentAssetPath, convertFileName));
-
- var destAsset = ScriptableObject.CreateInstance<SpriteLibrarySourceAsset>();
- destAsset.SetLibrary(new List<SpriteLibCategoryOverride>(sourceAsset.categories.Count));
- foreach (var sourceCat in sourceAsset.categories)
- {
- var destCat = new SpriteLibCategoryOverride()
- {
- overrideEntries = new List<SpriteCategoryEntryOverride>(sourceCat.categoryList.Count),
- name = sourceCat.name,
- entryOverrideCount = sourceCat.categoryList.Count,
- fromMain = false
- };
- destAsset.AddCategory(destCat);
- foreach (var entry in sourceCat.categoryList)
- {
- destCat.overrideEntries.Add(new SpriteCategoryEntryOverride()
- {
- name = entry.name,
- sprite = entry.sprite,
- fromMain = false,
- spriteOverride = entry.sprite
- });
- }
- }
-
- var assetBundle = AssetDatabase.GetImplicitAssetBundleName(path);
- if (!string.IsNullOrEmpty(assetBundle))
- {
- m_AssetBundlesNeedingUpgrade.Add(assetBundle);
- m_IndicesWithAssetBundleConnection.Add(pair.Key);
- m_Logger.Add($"{sourceAsset.name} is connected with the following AssetBundle: {assetBundle}.");
- }
-
- SpriteLibrarySourceAssetImporter.SaveSpriteLibrarySourceAsset(destAsset, convertFileName);
- newLibraryPaths.Add(new ValueTuple<int, string>(pair.Key, convertFileName));
- m_Logger.Add($"Created a new SpriteLibrary with the data of {sourceAsset.name}. The new SpriteLibrary is located at: {convertFileName}");
- }
-
- return newLibraryPaths;
- }
-
- static List<SpriteLibraryAsset> LoadNewLibraries(List<(int, string)> sourceAssetPaths)
- {
- var newLibraries = new List<SpriteLibraryAsset>();
- foreach (var path in sourceAssetPaths)
- {
- var newLibraryAsset = AssetDatabase.LoadAssetAtPath<SpriteLibraryAsset>(path.Item2);
- newLibraries.Add(newLibraryAsset);
- }
-
- return newLibraries;
- }
-
- void ReassignAssets(string[] assetPaths, List<SpriteLibraryAsset> oldLibraries, List<SpriteLibraryAsset> newLibraries)
- {
- var index = 0;
- foreach (var assetPath in assetPaths)
- {
- m_Logger.Add($"Scanning {assetPath} for components with SpriteLibraryAsset references in need of reassignment.");
- var ext = Path.GetExtension(assetPath);
- if (ext == ".prefab")
- UpgradePrefab(assetPath, oldLibraries, newLibraries, UpgradeGameObject);
- else if (ext == ".unity")
- UpgradeScene(assetPath, oldLibraries, newLibraries, UpgradeGameObject);
-
- var assetBundle = AssetDatabase.GetImplicitAssetBundleName(assetPath);
- if (!string.IsNullOrEmpty(assetBundle))
- {
- m_AssetBundlesNeedingUpgrade.Add(assetBundle);
- m_IndicesWithAssetBundleConnection.Add(index);
- }
-
- index++;
- }
- }
-
- static void UpgradePrefab(string path, List<SpriteLibraryAsset> oldLibraries, List<SpriteLibraryAsset> newLibraries,
- Action<GameObject, List<SpriteLibraryAsset>, List<SpriteLibraryAsset>> objectUpgrader)
- {
- var objects = AssetDatabase.LoadAllAssetsAtPath(path);
-
- var firstIndex = 0;
- for (var i = 0; i < objects.Length; i++)
- {
- if (objects[i] as GameObject)
- {
- firstIndex = i;
- break;
- }
- }
-
- if (!PrefabUtility.IsPartOfImmutablePrefab(objects[firstIndex]))
- {
- foreach (var obj in objects)
- {
- var go = obj as GameObject;
- if (go != null)
- {
- objectUpgrader(go, oldLibraries, newLibraries);
- }
- }
-
- var asset = objects[firstIndex] as GameObject;
- PrefabUtility.SavePrefabAsset(asset.transform.root.gameObject);
- }
- }
-
- static void UpgradeScene(string path, List<SpriteLibraryAsset> oldLibraries, List<SpriteLibraryAsset> newLibraries,
- Action<GameObject, List<SpriteLibraryAsset>, List<SpriteLibraryAsset>> objectUpgrader)
- {
- var scene = default(Scene);
- var openedByUser = false;
- for (var i = 0; i < SceneManager.sceneCount && !openedByUser; i++)
- {
- scene = SceneManager.GetSceneAt(i);
- if (path == scene.path)
- openedByUser = true;
- }
-
- if (!openedByUser)
- scene = EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
-
- var gameObjects = scene.GetRootGameObjects();
- foreach (var go in gameObjects)
- objectUpgrader(go, oldLibraries, newLibraries);
-
- EditorSceneManager.SaveScene(scene);
- if (!openedByUser)
- EditorSceneManager.CloseScene(scene, true);
- }
-
- void UpgradeGameObject(GameObject go, List<SpriteLibraryAsset> oldLibraries, List<SpriteLibraryAsset> newLibraries)
- {
- var types = k_SpriteLibraryReferenceLookup.Keys;
- foreach (var referenceType in types)
- {
- var components = go.GetComponentsInChildren(referenceType);
- foreach (var component in components)
- {
- if (PrefabUtility.IsPartOfPrefabInstance(component))
- continue;
-
- var fieldInfos = k_SpriteLibraryReferenceLookup[referenceType];
- foreach (var field in fieldInfos)
- {
- var asset = field.GetValue(component);
- if (asset is SpriteLibraryAsset spriteLibAsset)
- {
- var index = oldLibraries.FindIndex(x => x.GetHashCode() == spriteLibAsset.GetHashCode());
- if (index == -1)
- continue;
-
- field.SetValue(component, newLibraries[index]);
- m_Logger.Add($"Updated the SpriteLibraryAsset reference in {component.GetType()} on the GameObject {component.name}");
- }
- else if (asset is SpriteLibraryAsset[] spriteLibArray)
- {
- for (var i = 0; i < spriteLibArray.Length; ++i)
- {
- var index = oldLibraries.FindIndex(x => x.GetHashCode() == spriteLibArray[i].GetHashCode());
- if (index == -1)
- continue;
-
- spriteLibArray[i] = newLibraries[index];
- }
-
- field.SetValue(component, spriteLibArray);
- m_Logger.Add($"Updated the SpriteLibraryAsset[] reference in {component.GetType()} on the GameObject {component.name}");
- }
- else if (asset is List<SpriteLibraryAsset> spriteLibList)
- {
- for (var i = 0; i < spriteLibList.Count; ++i)
- {
- var index = oldLibraries.FindIndex(x => x.GetHashCode() == spriteLibList[i].GetHashCode());
- if (index == -1)
- continue;
-
- spriteLibList[i] = newLibraries[index];
- }
-
- field.SetValue(component, spriteLibList);
- m_Logger.Add($"Updated the List<SpriteLibraryAsset> reference in {component.GetType()} on the GameObject {component.name}");
- }
- }
- }
- }
- }
-
- void RemoveOldLibraries(List<SpriteLibraryAsset> oldLibraries)
- {
- foreach (var library in oldLibraries)
- {
- var path = AssetDatabase.GetAssetPath(library);
- var isPsbFile = UpgradeUtilities.IsPsbImportedFile(path);
- if (!string.IsNullOrEmpty(path) && !isPsbFile)
- {
- m_Logger.Add($"Deleting {path} from project");
- AssetDatabase.DeleteAsset(path);
- }
- }
- }
-
- // Leaving this in if we want to cleanup .psbs in the future
- void RemoveSpriteLibFromPsb(string path)
- {
- var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
-
- var factory = new SpriteDataProviderFactories();
- factory.Init();
- var dataProvider = factory.GetSpriteEditorDataProviderFromObject(texture);
- dataProvider.InitSpriteEditorDataProvider();
- if (dataProvider.targetObject == null)
- {
- m_Logger.Add($"Could not load the PSDImporter from the path: {path}. Aborting the Sprite Library cleanup inside the .psb.");
- return;
- }
-
- var so = new SerializedObject(dataProvider.targetObject);
- var property = so.FindProperty(k_PsbImporterCategoriesId);
- if (property != null && property.isArray)
- {
- property.arraySize = 0;
- so.ApplyModifiedPropertiesWithoutUndo();
- dataProvider.Apply();
- m_Logger.Add($"Removed the Sprite Library asset inside {path}");
-
- var assetImporter = dataProvider.targetObject as AssetImporter;
- assetImporter.SaveAndReimport();
- m_Logger.Add($"Saved and re-imported the file.");
- }
- else
- {
- m_Logger.Add($"Could not find any Sprite Library asset inside the .psb to cleanup.");
- }
- }
-
- void AddAssetBundlesToLog()
- {
- m_Logger.AddLineBreak();
- m_Logger.Add("[NOTE] The following AssetBundles need to be rebuilt:");
- foreach(var assetBundle in m_AssetBundlesNeedingUpgrade)
- m_Logger.Add(assetBundle);
- }
- }
- }
|