引言:
在unity3d的实际项目开发中,由于资源的增删改频繁,手动设置asset bundle name是一项繁琐且容易出错的工作,所以衍生出了开发自动化工具的需求。
工作原理:
以文件夹为目标,设置asset bundle name,在目标文件夹内的文件都会打进同一个asset bundle。
实现原理:
通过遍历Asset路径下的所有文件夹,收集所有的子文件夹列表,然后顺序设置asset bundle name。命名规格是将路径中的"\"替换为"_"。其中对文件夹的操作用到System.IO下面的接口。
另外添加了黑名单配置列表,用于过滤无需设置asset bundle name的文件夹。(例如导入的插件等)
特别的,为了避免资源冗余,仅对最低层的文件夹设置asset bundle name。
源代码:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class AutoGenerateAssetBundleName
{
/// <summary>
/// 黑名单
/// </summary>
static public string[] skip_dirs_all = { "testBlackList" };
[MenuItem("Asset Bundle/Auto generate asset bundle name", false, 1)]
public static void GenerateAssetBundleName()
{
string dataPath = Application.dataPath;
string root_path = "";
string sub_dir = "";
int position = dataPath.LastIndexOf(@"/");
if (position != -1)
{
root_path = dataPath.Substring(0, position + 1);
sub_dir = dataPath.Substring(position + 1);
}
ClearAssetBundleName(root_path, sub_dir);
Debug.Log("Begin GenerateAssetBundleName...");
List<string> OutPathList = new List<string>();
List<string> IncludeOutPathList = new List<string>();
OutPathList = GetFilterDirectories(@root_path, @sub_dir);
foreach(string AssetBundleName in OutPathList)
{
AssetImporter importer = AssetImporter.GetAtPath(AssetBundleName);
if (importer != null)
{
importer.assetBundleName = AssetBundleName.Replace('/', '_');
importer.assetBundleVariant = "";
}
}
AssetDatabase.Refresh();
Debug.Log("End GenerateAssetBundleName... Total asset bundle count: " + OutPathList.Count);
}
static List<string> GetFilterDirectories(string root_path, string sub_dir, bool bNeedSkip = true)
{
//需要过滤的文件夹
List<string> skip_dirs = new List<string>(skip_dirs_all);
string sub_folder_name = sub_dir;
int position = sub_dir.LastIndexOf(@"/");
if (position != -1)
sub_folder_name = sub_dir.Substring(position + 1);
if (bNeedSkip)
{
bool bSkipit = false;
foreach(string skip_dir in skip_dirs)
{
if (string.Compare(skip_dir, sub_folder_name, true) == 0)
{
bSkipit = true;
break;
}
}
if (bSkipit)
{
return new List<string>();
}
}
string[] dirs = Directory.GetDirectories(root_path + sub_dir, "*", SearchOption.TopDirectoryOnly);
// 提取文件夹名
string[] folder_names = new string[dirs.Length];
for (int i = 0; i < dirs.Length; ++i)
{
int pos = dirs[i].LastIndexOf(@"\");
if (pos != -1)
folder_names[i] = dirs[i].Substring(pos + 1);
}
List<string> filter_dirs = new List<string>();
if (dirs.Length == 0)
{
//没有子目录
//如果sub_folder_name不在skip_dirs内,则设置assetbundlename
bool bFindit = false;
foreach(string skip_dir in skip_dirs)
{
if (string.Compare(skip_dir, sub_folder_name, true) == 0)
{
bFindit = true;
break;
}
}
if (!bFindit)
{
Debug.Log("collect valid asset bundle name: " + sub_dir);
filter_dirs.Add(sub_dir);
}
return filter_dirs;
}
foreach (string folder_name in folder_names)
{
List<string> sub_filter_dirs = GetFilterDirectories(root_path, sub_dir + "/" + folder_name);
filter_dirs.AddRange(sub_filter_dirs);
}
return filter_dirs;
}
static void GetAllDirectories(string root_path, string sub_dir, ref List<string> outPathList)
{
string[] dirs = Directory.GetDirectories(root_path + sub_dir, "*", SearchOption.TopDirectoryOnly);
outPathList.Add(sub_dir);
if (dirs.Length > 0)
{
// 提取文件夹名
string[] folder_names = new string[dirs.Length];
for(int i = 0; i < dirs.Length; ++i)
{
int pos = dirs[i].LastIndexOf(@"\");
if (pos != -1)
folder_names[i] = dirs[i].Substring(pos + 1);
}
foreach(string folder_name in folder_names)
{
GetAllDirectories(root_path, sub_dir + "/" + folder_name, ref outPathList);
}
}
}
static void ClearAssetBundleName(string root_path, string sub_dir)
{
List<string> OutPathList = new List<string>();
GetAllDirectories(@root_path, @sub_dir, ref OutPathList);
foreach(string folder in OutPathList)
{
AssetImporter importer = AssetImporter.GetAtPath(folder);
if (importer != null)
{
importer.assetBundleName = "";
}
}
AssetDatabase.RemoveUnusedAssetBundleNames();
AssetDatabase.Refresh();
}
}
运行结果:
运行的log输出
文件夹的asset bundle name: