拓展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
以上知识分享,如有错误,欢迎指出,共同学习,共同进步。