Unity編輯器拓展之二十一:拓展Unity模組,打造私人工具庫(二)
阿新 • • 發佈:2019-01-30
拓展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倉庫:
以上知識分享,如有錯誤,歡迎指出,共同學習,共同進步。