1. 程式人生 > >Unity編輯器拓展之二十一:拓展Unity模組,打造私人工具庫(二)

Unity編輯器拓展之二十一:拓展Unity模組,打造私人工具庫(二)

拓展Unity模組,打造私人工具庫(二)

前言:

上一篇,實現了基本Unity模組拓展的功能,本篇將介紹如何通過反射來實現匯入UnityPackage

Gif示意圖

這裡寫圖片描述

程式匯入UnityPackage

通過查閱UnityEditor原始碼發現,UnityEditor名稱空間下有個EditorWindow的子類PackageImport,該類有個靜態函式ShowImportPackage如下:

public static void ShowImportPackage(string packagePath, ImportPackageItem[] items, string packageIconPath, bool
allowReInstall) { if (PackageImport.ValidateInput(items)) { PackageImport window = EditorWindow.GetWindow<PackageImport>(true, "Import Unity Package"); window.Init(packagePath, items, packageIconPath, allowReInstall); } }

該函式除了需要傳入package 的路徑外,還需要傳入 ImportPackageItem[](也就是該package的內容),通過在UnityEditor中搜索ShowImportPackage函式呼叫,發現在AssetDataBase類中有一個靜態函式ImportPackage用來匯入Package的,該函式中先呼叫PackageUtility.ExtractAndPrepareAssetList函式獲取到package裡內容的列表,然後在呼叫的匯入,當然此處還用到了interactive變數來控制是否開啟Import Window。而PackageUtility.ExtractAndPrepareAssetList詳細程式碼則是看不到了。

public static void ImportPackage(string packagePath, bool interactive)
{
    if (string.IsNullOrEmpty(packagePath))
    {
        throw new ArgumentException("Path can not be empty or null", "packagePath");
    }
    string packageIconPath;
    bool allowReInstall;
    ImportPackageItem[] array = PackageUtility.ExtractAndPrepareAssetList(packagePath, out
packageIconPath, out allowReInstall); if (array != null) { if (interactive) { PackageImport.ShowImportPackage(packagePath, array, packageIconPath, allowReInstall); } else { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(packagePath); PackageUtility.ImportPackageAssets(fileNameWithoutExtension, array, false); } } }

通過嘗試,一次匯入多個UnityPackage時,後一個會將前一個覆蓋掉(估計是匯入資源Unity需要載入並且編譯吧),所以目前工具只能單個匯入。

封裝一個Package2Folder類,用來匯入UnityPackage,只需呼叫ImportPackageToFolder函式即可。

這裡寫圖片描述

public class Package2Folder
    {
        #region reflection stuff

        private delegate AssetsItem[] ImportPackageStep1Delegate(string packagePath, out string packageIconPath);

        private static Type assetServerType;

        private static Type AssetServerType
        {
            get
            {
                if (assetServerType == null)
                {
                    assetServerType = typeof(MenuItem).Assembly.GetType("UnityEditor.AssetServer");
                }

                return assetServerType;
            }
        }

        private static ImportPackageStep1Delegate importPackageStep1;

        private static ImportPackageStep1Delegate ImportPackageStep1
        {
            get
            {
                if (importPackageStep1 == null)
                {
                    importPackageStep1 = (ImportPackageStep1Delegate)Delegate.CreateDelegate(
                        typeof(ImportPackageStep1Delegate),
                        null,
                        AssetServerType.GetMethod("ImportPackageStep1"));
                }

                return importPackageStep1;
            }
        }

        private static MethodInfo importPackageStep2MethodInfo;

        private static MethodInfo ImportPackageStep2MethodInfo
        {
            get
            {
                if (importPackageStep2MethodInfo == null)
                {
                    importPackageStep2MethodInfo = AssetServerType.GetMethod("ImportPackageStep2");
                }

                return importPackageStep2MethodInfo;
            }
        }

        private delegate object[] ExtractAndPrepareAssetListDelegate(string packagePath, out string packageIconPath,
            out bool allowReInstall);

        private static Type packageUtilityType;

        private static Type PackageUtilityType
        {
            get
            {
                if (packageUtilityType == null)
                {
                    packageUtilityType
                        = typeof(MenuItem).Assembly.GetType("UnityEditor.PackageUtility");
                }
                return packageUtilityType;
            }
        }

        private static ExtractAndPrepareAssetListDelegate extractAndPrepareAssetList;

        private static ExtractAndPrepareAssetListDelegate ExtractAndPrepareAssetList
        {
            get
            {
                if (extractAndPrepareAssetList == null)
                {
                    extractAndPrepareAssetList
                        = (ExtractAndPrepareAssetListDelegate)Delegate.CreateDelegate(
                            typeof(ExtractAndPrepareAssetListDelegate),
                            null,
                            PackageUtilityType.GetMethod("ExtractAndPrepareAssetList"));
                }

                return extractAndPrepareAssetList;
            }
        }

        private static FieldInfo destinationAssetPathFieldInfo;

        private static FieldInfo DestinationAssetPathFieldInfo
        {
            get
            {
                if (destinationAssetPathFieldInfo == null)
                {
                    Type importPackageItem
                        = typeof(MenuItem).Assembly.GetType("UnityEditor.ImportPackageItem");
                    destinationAssetPathFieldInfo
                        = importPackageItem.GetField("destinationAssetPath");
                }
                return destinationAssetPathFieldInfo;
            }
        }

        private static MethodInfo importPackageAssetsMethodInfo;

        private static MethodInfo ImportPackageAssetsMethodInfo
        {
            get
            {
                if (importPackageAssetsMethodInfo == null)
                {
                    // ImportPackageAssetsImmediately 是同步的匯入5.4以上版本可用
                    importPackageAssetsMethodInfo
                        = PackageUtilityType.GetMethod("ImportPackageAssetsImmediately") ??
                          PackageUtilityType.GetMethod("ImportPackageAssets");
                }

                return importPackageAssetsMethodInfo;
            }
        }

        private static MethodInfo showImportPackageMethodInfo;

        private static MethodInfo ShowImportPackageMethodInfo
        {
            get
            {
                if (showImportPackageMethodInfo == null)
                {
                    Type packageImport = typeof(MenuItem).Assembly.GetType("UnityEditor.PackageImport");
                    showImportPackageMethodInfo = packageImport.GetMethod("ShowImportPackage");
                }

                return showImportPackageMethodInfo;
            }
        }

        #endregion reflection stuff

        public static void ImportPackageToFolder(string packagePath, string selectedFolderPath, bool interactive)
        {
            string packageIconPath;
            bool allowReInstall;
            if (AssetServerType != null && AssetServerType.GetMethod("ImportPackageStep1") != null)
                IsOlder53VersionAPI = true;
            else
                IsOlder53VersionAPI = false;
            //IsOlder53VersionAPI = false;
            object[] assetsItems = ExtractAssetsFromPackage(packagePath, out packageIconPath, out allowReInstall);
            if (assetsItems == null) return;
            foreach (object item in assetsItems)
            {
                ChangeAssetItemPath(item, selectedFolderPath);
            }

            if (interactive)
            {
                ShowImportPackageWindow(packagePath, assetsItems, packageIconPath, allowReInstall);
            }
            else
            {
                ImportPackageSilently(assetsItems);
            }
        }

        private static bool IsOlder53VersionAPI = false;

        public static object[] ExtractAssetsFromPackage(string path, out string packageIconPath,
            out bool allowReInstall)
        {
            if (IsOlder53VersionAPI)
            {
                AssetsItem[] array = ImportPackageStep1(path, out packageIconPath);
                allowReInstall = false;
                return array;
            }
            else
            {
                object[] array = ExtractAndPrepareAssetList(path, out packageIconPath, out allowReInstall);
                return array;
            }
        }

        private static void ChangeAssetItemPath(object assetItem, string selectedFolderPath)
        {
            if (IsOlder53VersionAPI)
            {
                AssetsItem item = (AssetsItem)assetItem;
                item.exportedAssetPath = selectedFolderPath + item.exportedAssetPath.Remove(0, 6);
                item.pathName = selectedFolderPath + item.pathName.Remove(0, 6);
            }
            else
            {
                string destinationPath
                    = (string)DestinationAssetPathFieldInfo.GetValue(assetItem);
                destinationPath
                    = selectedFolderPath + destinationPath.Remove(0, 6);
                DestinationAssetPathFieldInfo.SetValue(assetItem, destinationPath);
            }
        }

        public static void ShowImportPackageWindow(string path, object[] array, string packageIconPath,
            bool allowReInstall)
        {
            if (IsOlder53VersionAPI)
            {
                ShowImportPackageMethodInfo.Invoke(null, new object[] { path, array, packageIconPath });
            }
            else
            {
                ShowImportPackageMethodInfo.Invoke(null, new object[] { path, array, packageIconPath, allowReInstall });
            }
        }

        public static void ImportPackageSilently(object[] assetsItems)
        {
            if (IsOlder53VersionAPI)
            {
                ImportPackageStep2MethodInfo.Invoke(null, new object[] { assetsItems, false });
            }
            else
            {
                ImportPackageAssetsMethodInfo.Invoke(null, new object[] { assetsItems, false });
            }
        }

        private static string GetSelectedFolderPath()
        {
            UnityEngine.Object obj = Selection.activeObject;
            if (obj == null) return null;
            string path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
            return !Directory.Exists(path) ? null : path;
        }
    }

參考文獻

工具下載

git倉庫:

以上知識分享,如有錯誤,歡迎指出,共同學習,共同進步。