JingFengJi
for me
FRIENDS
llcat

Unity编辑器拓展之二十一:拓展Unity模块,打造私人工具库(二)

2018-08-22

拓展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;
        }
    }

参考文献

【UnityEditor 编辑器间快速复制粘贴】: https://539go.com/2018/02/04/Unity-QuickCopy/
引用了该文章中的UnityPackage导入代码。

工具下载

git仓库:

https://github.com/JingFengJi/UnityCenterTool

以上知识分享,如有错误,欢迎指出,共同学习,共同进步。

Author: Mr.Ding

Link: https://jingfengji.github.io/2018/08/22/Unity编辑器拓展之二十一:拓展Unity模块,打造私人工具库(二)/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Unity编辑器拓展之二十二:基于TexturePacker的一键打图集工具
NextPost >
Unity编辑器拓展之二十:拓展Unity模块,打造私人工具库(一)
CATALOG
  1. 1. 拓展Unity模块,打造私人工具库(二)
    1. 1.1. 前言:
    2. 1.2. Gif示意图
    3. 1.3. 程序导入UnityPackage
    4. 1.4. 参考文献
    5. 1.5. 工具下载