Update AssetBundleCollector

AssetBundleGrouper变更为AssetBundleCollector
This commit is contained in:
hevinci
2022-05-04 21:24:51 +08:00
parent d592fb96a6
commit eafdb8cd31
40 changed files with 247 additions and 247 deletions

View File

@@ -0,0 +1,252 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
namespace YooAsset.Editor
{
[Serializable]
public class AssetBundleCollector
{
/// <summary>
/// 收集路径
/// 注意:支持文件夹或单个资源文件
/// </summary>
public string CollectPath = string.Empty;
/// <summary>
/// 收集器类型
/// </summary>
public ECollectorType CollectorType = ECollectorType.MainAssetCollector;
/// <summary>
/// 寻址规则类名
/// </summary>
public string AddressRuleName = nameof(AddressByFileName);
/// <summary>
/// 打包规则类名
/// </summary>
public string PackRuleName = nameof(PackDirectory);
/// <summary>
/// 过滤规则类名
/// </summary>
public string FilterRuleName = nameof(CollectAll);
/// <summary>
/// 资源分类标签
/// </summary>
public string AssetTags = string.Empty;
/// <summary>
/// 收集器是否有效
/// </summary>
public bool IsValid()
{
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(CollectPath) == null)
return false;
if (CollectorType == ECollectorType.None)
return false;
if (AssetBundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
return false;
if (AssetBundleCollectorSettingData.HasPackRuleName(PackRuleName) == false)
return false;
if (AssetBundleCollectorSettingData.HasFilterRuleName(FilterRuleName) == false)
return false;
return true;
}
/// <summary>
/// 检测配置错误
/// </summary>
public void CheckConfigError()
{
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(CollectPath) == null)
throw new Exception($"Invalid collect path : {CollectPath}");
if (CollectorType == ECollectorType.None)
throw new Exception($"{nameof(ECollectorType)}.{ECollectorType.None} is invalid in collector : {CollectPath}");
if (AssetBundleCollectorSettingData.HasPackRuleName(PackRuleName) == false)
throw new Exception($"Invalid {nameof(IPackRule)} class type : {PackRuleName} in collector : {CollectPath}");
if (AssetBundleCollectorSettingData.HasFilterRuleName(FilterRuleName) == false)
throw new Exception($"Invalid {nameof(IFilterRule)} class type : {FilterRuleName} in collector : {CollectPath}");
if (AssetBundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
throw new Exception($"Invalid {nameof(IAddressRule)} class type : {AddressRuleName} in collector : {CollectPath}");
}
/// <summary>
/// 获取打包收集的资源文件
/// </summary>
public List<CollectAssetInfo> GetAllCollectAssets(AssetBundleCollectorGroup group)
{
Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(1000);
bool isRawAsset = PackRuleName == nameof(PackRawFile);
// 检测原生资源包的收集器类型
if (isRawAsset && CollectorType != ECollectorType.MainAssetCollector)
throw new Exception($"The raw file must be set to {nameof(ECollectorType)}.{ECollectorType.MainAssetCollector} : {CollectPath}");
if (string.IsNullOrEmpty(CollectPath))
throw new Exception($"The collect path is null or empty in group : {group.GroupName}");
// 收集打包资源
if (AssetDatabase.IsValidFolder(CollectPath))
{
string collectDirectory = CollectPath;
string[] findAssets = EditorTools.FindAssets(EAssetSearchType.All, collectDirectory);
foreach (string assetPath in findAssets)
{
if (IsValidateAsset(assetPath) && IsCollectAsset(assetPath))
{
if (result.ContainsKey(assetPath) == false)
{
var collectAssetInfo = CreateCollectAssetInfo(group, assetPath, isRawAsset);
result.Add(assetPath, collectAssetInfo);
}
else
{
throw new Exception($"The collecting asset file is existed : {assetPath} in collector : {CollectPath}");
}
}
}
}
else
{
string assetPath = CollectPath;
if (IsValidateAsset(assetPath) && IsCollectAsset(assetPath))
{
var collectAssetInfo = CreateCollectAssetInfo(group, assetPath, isRawAsset);
result.Add(assetPath, collectAssetInfo);
}
else
{
throw new Exception($"The collecting single asset file is invalid : {assetPath} in collector : {CollectPath}");
}
}
// 检测可寻址地址是否重复
if (AssetBundleCollectorSettingData.Setting.EnableAddressable)
{
HashSet<string> adressTemper = new HashSet<string>();
foreach (var collectInfoPair in result)
{
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{
string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
else
throw new Exception($"The address is existed : {address} in collector : {CollectPath}");
}
}
}
// 返回列表
return result.Values.ToList();
}
private CollectAssetInfo CreateCollectAssetInfo(AssetBundleCollectorGroup group, string assetPath, bool isRawAsset)
{
string address = GetAddress(group, assetPath);
string bundleName = GetBundleName(group, assetPath);
List<string> assetTags = GetAssetTags(group);
CollectAssetInfo collectAssetInfo = new CollectAssetInfo(CollectorType, bundleName, address, assetPath, assetTags, isRawAsset);
collectAssetInfo.DependAssets = GetAllDependencies(assetPath);
return collectAssetInfo;
}
private bool IsValidateAsset(string assetPath)
{
if (assetPath.StartsWith("Assets/") == false && assetPath.StartsWith("Packages/") == false)
return false;
if (AssetDatabase.IsValidFolder(assetPath))
return false;
// 注意:忽略编辑器下的类型资源
Type type = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (type == typeof(LightingDataAsset))
return false;
string ext = System.IO.Path.GetExtension(assetPath);
if (ext == "" || ext == ".dll" || ext == ".cs" || ext == ".js" || ext == ".boo" || ext == ".meta" || ext == ".cginc")
return false;
return true;
}
private bool IsCollectAsset(string assetPath)
{
// 如果收集全路径着色器
if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
{
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
return true;
}
// 根据规则设置过滤资源文件
IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);
return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath));
}
private string GetAddress(AssetBundleCollectorGroup group, string assetPath)
{
if (CollectorType != ECollectorType.MainAssetCollector)
return string.Empty;
IAddressRule addressRuleInstance = AssetBundleCollectorSettingData.GetAddressRuleInstance(AddressRuleName);
string adressValue = addressRuleInstance.GetAssetAddress(new AddressRuleData(assetPath, CollectPath, group.GroupName));
return adressValue;
}
private string GetBundleName(AssetBundleCollectorGroup group, string assetPath)
{
// 如果自动收集所有的着色器
if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
{
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
{
string bundleName = AssetBundleCollectorSettingData.Setting.ShadersBundleName;
return EditorTools.GetRegularPath(bundleName).ToLower();
}
}
// 根据规则设置获取资源包名称
{
IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, group.GroupName));
return EditorTools.GetRegularPath(bundleName).ToLower();
}
}
private List<string> GetAssetTags(AssetBundleCollectorGroup group)
{
List<string> tags = StringUtility.StringToStringList(group.AssetTags, ';');
List<string> temper = StringUtility.StringToStringList(AssetTags, ';');
tags.AddRange(temper);
return tags;
}
private List<string> GetAllDependencies(string mainAssetPath)
{
List<string> result = new List<string>();
string[] depends = AssetDatabase.GetDependencies(mainAssetPath, true);
foreach (string assetPath in depends)
{
if (IsValidateAsset(assetPath))
{
// 注意:排除主资源对象
if (assetPath != mainAssetPath)
result.Add(assetPath);
}
}
return result;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f79866c315d53ef4480d6fa4083c09ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,166 @@
using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
public class AssetBundleCollectorConfig
{
public const string XmlShader = "Shader";
public const string XmlAutoCollectShader = "AutoCollectShader";
public const string XmlShaderBundleName = "ShaderBundleName";
public const string XmlGroup = "Group";
public const string XmlGroupName = "GroupName";
public const string XmlGroupDesc = "GroupDesc";
public const string XmlCollector = "Collector";
public const string XmlCollectPath = "CollectPath";
public const string XmlCollectorType = "CollectType";
public const string XmlAddressRule = "AddressRule";
public const string XmlPackRule = "PackRule";
public const string XmlFilterRule = "FilterRule";
public const string XmlAssetTags = "AssetTags";
/// <summary>
/// 导入XML配置表
/// </summary>
public static void ImportXmlConfig(string filePath)
{
if (File.Exists(filePath) == false)
throw new FileNotFoundException(filePath);
if (Path.GetExtension(filePath) != ".xml")
throw new Exception($"Only support xml : {filePath}");
// 加载配置文件
XmlDocument xml = new XmlDocument();
xml.Load(filePath);
XmlElement root = xml.DocumentElement;
// 读取着色器配置
bool autoCollectShaders = false;
string shaderBundleName = string.Empty;
var shaderNodeList = root.GetElementsByTagName(XmlShader);
if (shaderNodeList.Count > 0)
{
XmlElement shaderElement = shaderNodeList[0] as XmlElement;
if (shaderElement.HasAttribute(XmlAutoCollectShader) == false)
throw new Exception($"Not found attribute {XmlAutoCollectShader} in {XmlShader}");
if (shaderElement.HasAttribute(XmlShaderBundleName) == false)
throw new Exception($"Not found attribute {XmlShaderBundleName} in {XmlShader}");
autoCollectShaders = shaderElement.GetAttribute(XmlAutoCollectShader) == "True" ? true : false;
shaderBundleName = shaderElement.GetAttribute(XmlShaderBundleName);
}
// 读取分组配置
List<AssetBundleCollectorGroup> groupTemper = new List<AssetBundleCollectorGroup>();
var groupNodeList = root.GetElementsByTagName(XmlGroup);
foreach (var groupNode in groupNodeList)
{
XmlElement groupElement = groupNode as XmlElement;
if (groupElement.HasAttribute(XmlGroupName) == false)
throw new Exception($"Not found attribute {XmlGroupName} in {XmlGroup}");
if (groupElement.HasAttribute(XmlGroupDesc) == false)
throw new Exception($"Not found attribute {XmlGroupDesc} in {XmlGroup}");
if (groupElement.HasAttribute(XmlAssetTags) == false)
throw new Exception($"Not found attribute {XmlAssetTags} in {XmlGroup}");
AssetBundleCollectorGroup group = new AssetBundleCollectorGroup();
group.GroupName = groupElement.GetAttribute(XmlGroupName);
group.GroupDesc = groupElement.GetAttribute(XmlGroupDesc);
group.AssetTags = groupElement.GetAttribute(XmlAssetTags);
groupTemper.Add(group);
// 读取收集器配置
var collectorNodeList = groupElement.GetElementsByTagName(XmlCollector);
foreach (var collectorNode in collectorNodeList)
{
XmlElement collectorElement = collectorNode as XmlElement;
if (collectorElement.HasAttribute(XmlCollectPath) == false)
throw new Exception($"Not found attribute {XmlCollectPath} in {XmlCollector}");
if (collectorElement.HasAttribute(XmlCollectorType) == false)
throw new Exception($"Not found attribute {XmlCollectorType} in {XmlCollector}");
if (collectorElement.HasAttribute(XmlAddressRule) == false)
throw new Exception($"Not found attribute {XmlAddressRule} in {XmlCollector}");
if (collectorElement.HasAttribute(XmlPackRule) == false)
throw new Exception($"Not found attribute {XmlPackRule} in {XmlCollector}");
if (collectorElement.HasAttribute(XmlFilterRule) == false)
throw new Exception($"Not found attribute {XmlFilterRule} in {XmlCollector}");
if (collectorElement.HasAttribute(XmlAssetTags) == false)
throw new Exception($"Not found attribute {XmlAssetTags} in {XmlCollector}");
AssetBundleCollector collector = new AssetBundleCollector();
collector.CollectPath = collectorElement.GetAttribute(XmlCollectPath);
collector.CollectorType = StringUtility.NameToEnum<ECollectorType>(collectorElement.GetAttribute(XmlCollectorType));
collector.AddressRuleName = collectorElement.GetAttribute(XmlAddressRule);
collector.PackRuleName = collectorElement.GetAttribute(XmlPackRule);
collector.FilterRuleName = collectorElement.GetAttribute(XmlFilterRule);
collector.AssetTags = collectorElement.GetAttribute(XmlAssetTags); ;
group.Collectors.Add(collector);
}
}
// 保存配置数据
AssetBundleCollectorSettingData.ClearAll();
AssetBundleCollectorSettingData.Setting.AutoCollectShaders = autoCollectShaders;
AssetBundleCollectorSettingData.Setting.ShadersBundleName = shaderBundleName;
AssetBundleCollectorSettingData.Setting.Groups.AddRange(groupTemper);
AssetBundleCollectorSettingData.SaveFile();
Debug.Log($"导入配置完毕!");
}
/// <summary>
/// 导出XML配置表
/// </summary>
public static void ExportXmlConfig(string savePath)
{
if (File.Exists(savePath))
File.Delete(savePath);
StringBuilder sb = new StringBuilder();
sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
sb.AppendLine("<root>");
sb.AppendLine("</root>");
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(sb.ToString());
XmlElement root = xmlDoc.DocumentElement;
// 设置着色器配置
var shaderElement = xmlDoc.CreateElement(XmlShader);
shaderElement.SetAttribute(XmlAutoCollectShader, AssetBundleCollectorSettingData.Setting.AutoCollectShaders.ToString());
shaderElement.SetAttribute(XmlShaderBundleName, AssetBundleCollectorSettingData.Setting.ShadersBundleName);
// 设置分组配置
foreach (var group in AssetBundleCollectorSettingData.Setting.Groups)
{
var groupElement = xmlDoc.CreateElement(XmlGroup);
groupElement.SetAttribute(XmlGroupName, group.GroupName);
groupElement.SetAttribute(XmlGroupDesc, group.GroupDesc);
groupElement.SetAttribute(XmlAssetTags, group.AssetTags);
root.AppendChild(groupElement);
// 设置收集器配置
foreach (var collector in group.Collectors)
{
var collectorElement = xmlDoc.CreateElement(XmlCollector);
collectorElement.SetAttribute(XmlCollectPath, collector.CollectPath);
collectorElement.SetAttribute(XmlCollectorType, collector.CollectorType.ToString());
collectorElement.SetAttribute(XmlAddressRule, collector.AddressRuleName);
collectorElement.SetAttribute(XmlPackRule, collector.PackRuleName);
collectorElement.SetAttribute(XmlFilterRule, collector.FilterRuleName);
collectorElement.SetAttribute(XmlAssetTags, collector.AssetTags);
groupElement.AppendChild(collectorElement);
}
}
// 生成配置文件
xmlDoc.Save(savePath);
Debug.Log($"导出配置完毕!");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9a030381c5944145a285c3212153ceb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
namespace YooAsset.Editor
{
[Serializable]
public class AssetBundleCollectorGroup
{
/// <summary>
/// 分组名称
/// </summary>
public string GroupName = string.Empty;
/// <summary>
/// 分组描述
/// </summary>
public string GroupDesc = string.Empty;
/// <summary>
/// 资源分类标签
/// </summary>
public string AssetTags = string.Empty;
/// <summary>
/// 分组的收集器列表
/// </summary>
public List<AssetBundleCollector> Collectors = new List<AssetBundleCollector>();
/// <summary>
/// 检测配置错误
/// </summary>
public void CheckConfigError()
{
foreach (var collector in Collectors)
{
collector.CheckConfigError();
}
}
/// <summary>
/// 获取打包收集的资源文件
/// </summary>
public List<CollectAssetInfo> GetAllCollectAssets()
{
Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(10000);
// 收集打包资源
foreach (var collector in Collectors)
{
var temper = collector.GetAllCollectAssets(this);
foreach (var assetInfo in temper)
{
if (result.ContainsKey(assetInfo.AssetPath) == false)
result.Add(assetInfo.AssetPath, assetInfo);
else
throw new Exception($"The collecting asset file is existed : {assetInfo.AssetPath} in group : {GroupName}");
}
}
// 检测可寻址地址是否重复
if (AssetBundleCollectorSettingData.Setting.EnableAddressable)
{
HashSet<string> adressTemper = new HashSet<string>();
foreach (var collectInfoPair in result)
{
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{
string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
else
throw new Exception($"The address is existed : {address} in group : {GroupName}");
}
}
}
// 返回列表
return result.Values.ToList();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e9f7615a761107d4ebf96d66be2f6b45
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace YooAsset.Editor
{
public class AssetBundleCollectorSetting : ScriptableObject
{
/// <summary>
/// 是否启用可寻址资源定位
/// </summary>
public bool EnableAddressable = false;
/// <summary>
/// 自动收集着色器
/// </summary>
public bool AutoCollectShaders = true;
/// <summary>
/// 自动收集的着色器资源包名称
/// </summary>
public string ShadersBundleName = "myshaders";
/// <summary>
/// 分组列表
/// </summary>
public List<AssetBundleCollectorGroup> Groups = new List<AssetBundleCollectorGroup>();
/// <summary>
/// 检测配置错误
/// </summary>
public void CheckConfigError()
{
foreach (var group in Groups)
{
group.CheckConfigError();
}
}
/// <summary>
/// 获取打包收集的资源文件
/// </summary>
public List<CollectAssetInfo> GetAllCollectAssets()
{
Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(10000);
// 收集打包资源
foreach (var group in Groups)
{
var temper = group.GetAllCollectAssets();
foreach (var assetInfo in temper)
{
if (result.ContainsKey(assetInfo.AssetPath) == false)
result.Add(assetInfo.AssetPath, assetInfo);
else
throw new Exception($"The collecting asset file is existed : {assetInfo.AssetPath} in group setting.");
}
}
// 检测可寻址地址是否重复
if (EnableAddressable)
{
HashSet<string> adressTemper = new HashSet<string>();
foreach (var collectInfoPair in result)
{
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{
string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
else
throw new Exception($"The address is existed : {address} in group setting.");
}
}
}
// 返回列表
return result.Values.ToList();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 185f6993d5150494d98da50e26cb1c25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,352 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
namespace YooAsset.Editor
{
public class AssetBundleCollectorSettingData
{
private static readonly Dictionary<string, System.Type> _cacheAddressRuleTypes = new Dictionary<string, System.Type>();
private static readonly Dictionary<string, IAddressRule> _cacheAddressRuleInstance = new Dictionary<string, IAddressRule>();
private static readonly Dictionary<string, System.Type> _cachePackRuleTypes = new Dictionary<string, System.Type>();
private static readonly Dictionary<string, IPackRule> _cachePackRuleInstance = new Dictionary<string, IPackRule>();
private static readonly Dictionary<string, System.Type> _cacheFilterRuleTypes = new Dictionary<string, System.Type>();
private static readonly Dictionary<string, IFilterRule> _cacheFilterRuleInstance = new Dictionary<string, IFilterRule>();
/// <summary>
/// 配置数据是否被修改
/// </summary>
public static bool IsDirty { private set; get; } = false;
private static AssetBundleCollectorSetting _setting = null;
public static AssetBundleCollectorSetting Setting
{
get
{
if (_setting == null)
LoadSettingData();
return _setting;
}
}
public static List<string> GetAddressRuleNames()
{
if (_setting == null)
LoadSettingData();
List<string> names = new List<string>();
foreach (var pair in _cacheAddressRuleTypes)
{
names.Add(pair.Key);
}
return names;
}
public static List<string> GetPackRuleNames()
{
if (_setting == null)
LoadSettingData();
List<string> names = new List<string>();
foreach (var pair in _cachePackRuleTypes)
{
names.Add(pair.Key);
}
return names;
}
public static List<string> GetFilterRuleNames()
{
if (_setting == null)
LoadSettingData();
List<string> names = new List<string>();
foreach (var pair in _cacheFilterRuleTypes)
{
names.Add(pair.Key);
}
return names;
}
public static bool HasAddressRuleName(string ruleName)
{
foreach (var pair in _cacheAddressRuleTypes)
{
if (pair.Key == ruleName)
return true;
}
return false;
}
public static bool HasPackRuleName(string ruleName)
{
foreach (var pair in _cachePackRuleTypes)
{
if (pair.Key == ruleName)
return true;
}
return false;
}
public static bool HasFilterRuleName(string ruleName)
{
foreach (var pair in _cacheFilterRuleTypes)
{
if (pair.Key == ruleName)
return true;
}
return false;
}
/// <summary>
/// 加载配置文件
/// </summary>
private static void LoadSettingData()
{
// 加载配置文件
string settingFilePath = $"{EditorTools.GetYooAssetSettingPath()}/{nameof(AssetBundleCollectorSetting)}.asset";
_setting = AssetDatabase.LoadAssetAtPath<AssetBundleCollectorSetting>(settingFilePath);
if (_setting == null)
{
Debug.LogWarning($"Create new {nameof(AssetBundleCollectorSetting)}.asset : {settingFilePath}");
_setting = ScriptableObject.CreateInstance<AssetBundleCollectorSetting>();
EditorTools.CreateFileDirectory(settingFilePath);
AssetDatabase.CreateAsset(Setting, settingFilePath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
else
{
Debug.Log($"Load {nameof(AssetBundleCollectorSetting)}.asset ok");
}
// IPackRule
{
// 清空缓存集合
_cachePackRuleTypes.Clear();
_cachePackRuleInstance.Clear();
// 获取所有类型
List<Type> types = new List<Type>(100)
{
typeof(PackSeparately),
typeof(PackDirectory),
typeof(PackTopDirectory),
typeof(PackCollector),
typeof(PackGroup),
typeof(PackRawFile),
};
TypeCache.TypeCollection collection = TypeCache.GetTypesDerivedFrom<IPackRule>();
var customTypes = collection.ToList();
types.AddRange(customTypes);
for (int i = 0; i < types.Count; i++)
{
Type type = types[i];
if (_cachePackRuleTypes.ContainsKey(type.Name) == false)
_cachePackRuleTypes.Add(type.Name, type);
}
}
// IFilterRule
{
// 清空缓存集合
_cacheFilterRuleTypes.Clear();
_cacheFilterRuleInstance.Clear();
// 获取所有类型
List<Type> types = new List<Type>(100)
{
typeof(CollectAll),
typeof(CollectScene),
typeof(CollectPrefab),
typeof(CollectSprite)
};
TypeCache.TypeCollection collection = TypeCache.GetTypesDerivedFrom<IFilterRule>();
var customTypes = collection.ToList();
types.AddRange(customTypes);
for (int i = 0; i < types.Count; i++)
{
Type type = types[i];
if (_cacheFilterRuleTypes.ContainsKey(type.Name) == false)
_cacheFilterRuleTypes.Add(type.Name, type);
}
}
// IAddressRule
{
// 清空缓存集合
_cacheAddressRuleTypes.Clear();
_cacheAddressRuleInstance.Clear();
// 获取所有类型
List<Type> types = new List<Type>(100)
{
typeof(AddressByFileName),
typeof(AddressByCollectorAndFileName),
typeof(AddressByGroupAndFileName)
};
TypeCache.TypeCollection collection = TypeCache.GetTypesDerivedFrom<IAddressRule>();
var customTypes = collection.ToList();
types.AddRange(customTypes);
for (int i = 0; i < types.Count; i++)
{
Type type = types[i];
if (_cacheAddressRuleTypes.ContainsKey(type.Name) == false)
_cacheAddressRuleTypes.Add(type.Name, type);
}
}
}
/// <summary>
/// 存储文件
/// </summary>
public static void SaveFile()
{
if (Setting != null)
{
IsDirty = false;
EditorUtility.SetDirty(Setting);
AssetDatabase.SaveAssets();
Debug.Log($"{nameof(AssetBundleCollectorSetting)}.asset is saved!");
}
}
/// <summary>
/// 清空所有数据
/// </summary>
public static void ClearAll()
{
Setting.AutoCollectShaders = false;
Setting.ShadersBundleName = string.Empty;
Setting.Groups.Clear();
SaveFile();
}
// 实例类相关
public static IAddressRule GetAddressRuleInstance(string ruleName)
{
if (_cacheAddressRuleInstance.TryGetValue(ruleName, out IAddressRule instance))
return instance;
// 如果不存在创建类的实例
if (_cacheAddressRuleTypes.TryGetValue(ruleName, out Type type))
{
instance = (IAddressRule)Activator.CreateInstance(type);
_cacheAddressRuleInstance.Add(ruleName, instance);
return instance;
}
else
{
throw new Exception($"{nameof(IAddressRule)}类型无效:{ruleName}");
}
}
public static IPackRule GetPackRuleInstance(string ruleName)
{
if (_cachePackRuleInstance.TryGetValue(ruleName, out IPackRule instance))
return instance;
// 如果不存在创建类的实例
if (_cachePackRuleTypes.TryGetValue(ruleName, out Type type))
{
instance = (IPackRule)Activator.CreateInstance(type);
_cachePackRuleInstance.Add(ruleName, instance);
return instance;
}
else
{
throw new Exception($"{nameof(IPackRule)}类型无效:{ruleName}");
}
}
public static IFilterRule GetFilterRuleInstance(string ruleName)
{
if (_cacheFilterRuleInstance.TryGetValue(ruleName, out IFilterRule instance))
return instance;
// 如果不存在创建类的实例
if (_cacheFilterRuleTypes.TryGetValue(ruleName, out Type type))
{
instance = (IFilterRule)Activator.CreateInstance(type);
_cacheFilterRuleInstance.Add(ruleName, instance);
return instance;
}
else
{
throw new Exception($"{nameof(IFilterRule)}类型无效:{ruleName}");
}
}
// 可寻址编辑相关
public static void ModifyAddressable(bool enableAddressable)
{
Setting.EnableAddressable = enableAddressable;
IsDirty = true;
}
// 着色器编辑相关
public static void ModifyShader(bool isCollectAllShaders, string shadersBundleName)
{
Setting.AutoCollectShaders = isCollectAllShaders;
Setting.ShadersBundleName = shadersBundleName;
IsDirty = true;
}
// 资源分组编辑相关
public static void CreateGroup(string groupName)
{
AssetBundleCollectorGroup group = new AssetBundleCollectorGroup();
group.GroupName = groupName;
Setting.Groups.Add(group);
IsDirty = true;
}
public static void RemoveGroup(AssetBundleCollectorGroup group)
{
if (Setting.Groups.Remove(group))
{
IsDirty = true;
}
else
{
Debug.LogWarning($"Failed remove group : {group.GroupName}");
}
}
public static void ModifyGroup(AssetBundleCollectorGroup group)
{
if (group != null)
{
IsDirty = true;
}
}
// 资源收集器编辑相关
public static void CreateCollector(AssetBundleCollectorGroup group, string collectPath)
{
AssetBundleCollector collector = new AssetBundleCollector();
collector.CollectPath = collectPath;
group.Collectors.Add(collector);
IsDirty = true;
}
public static void RemoveCollector(AssetBundleCollectorGroup group, AssetBundleCollector collector)
{
if (group.Collectors.Remove(collector))
{
IsDirty = true;
}
else
{
Debug.LogWarning($"Failed remove collector : {collector.CollectPath}");
}
}
public static void ModifyCollector(AssetBundleCollectorGroup group, AssetBundleCollector collector)
{
if (group != null && collector != null)
{
IsDirty = true;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2fa91f25d246411459816310b09480a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,607 @@
#if UNITY_2019_4_OR_NEWER
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
public class AssetBundleCollectorWindow : EditorWindow
{
[MenuItem("YooAsset/AssetBundle Collector", false, 101)]
public static void ShowExample()
{
AssetBundleCollectorWindow window = GetWindow<AssetBundleCollectorWindow>("资源包收集工具", true, EditorDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600);
}
private List<string> _collectorTypeList;
private List<string> _addressRuleList;
private List<string> _packRuleList;
private List<string> _filterRuleList;
private ListView _groupListView;
private ScrollView _collectorScrollView;
private Toggle _enableAddressableToogle;
private Toggle _autoCollectShaderToogle;
private TextField _shaderBundleNameTxt;
private TextField _groupNameTxt;
private TextField _groupDescTxt;
private TextField _groupAssetTagsTxt;
private VisualElement _groupContainer;
public void CreateGUI()
{
Undo.undoRedoPerformed -= RefreshWindow;
Undo.undoRedoPerformed += RefreshWindow;
VisualElement root = this.rootVisualElement;
_collectorTypeList = new List<string>()
{
$"{nameof(ECollectorType.MainAssetCollector)}",
$"{nameof(ECollectorType.StaticAssetCollector)}",
$"{nameof(ECollectorType.DependAssetCollector)}"
};
_addressRuleList = AssetBundleCollectorSettingData.GetAddressRuleNames();
_packRuleList = AssetBundleCollectorSettingData.GetPackRuleNames();
_filterRuleList = AssetBundleCollectorSettingData.GetFilterRuleNames();
// 加载布局文件
string rootPath = EditorTools.GetYooAssetSourcePath();
string uxml = $"{rootPath}/Editor/AssetBundleCollector/{nameof(AssetBundleCollectorWindow)}.uxml";
var visualAsset = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxml);
if (visualAsset == null)
{
Debug.LogError($"Not found {nameof(AssetBundleCollectorWindow)}.uxml : {uxml}");
return;
}
visualAsset.CloneTree(root);
try
{
// 导入导出按钮
var exportBtn = root.Q<Button>("ExportButton");
exportBtn.clicked += ExportBtn_clicked;
var importBtn = root.Q<Button>("ImportButton");
importBtn.clicked += ImportBtn_clicked;
// 公共设置相关
_enableAddressableToogle = root.Q<Toggle>("EnableAddressable");
_enableAddressableToogle.RegisterValueChangedCallback(evt =>
{
AssetBundleCollectorSettingData.ModifyAddressable(evt.newValue);
});
_autoCollectShaderToogle = root.Q<Toggle>("AutoCollectShader");
_autoCollectShaderToogle.RegisterValueChangedCallback(evt =>
{
AssetBundleCollectorSettingData.ModifyShader(evt.newValue, _shaderBundleNameTxt.value);
_shaderBundleNameTxt.SetEnabled(evt.newValue);
});
_shaderBundleNameTxt = root.Q<TextField>("ShaderBundleName");
_shaderBundleNameTxt.RegisterValueChangedCallback(evt =>
{
AssetBundleCollectorSettingData.ModifyShader(_autoCollectShaderToogle.value, evt.newValue);
});
// 分组列表相关
_groupListView = root.Q<ListView>("GroupListView");
_groupListView.makeItem = MakeGroupListViewItem;
_groupListView.bindItem = BindGroupListViewItem;
#if UNITY_2020_1_OR_NEWER
_groupListView.onSelectionChange += GroupListView_onSelectionChange;
#else
_groupListView.onSelectionChanged += GroupListView_onSelectionChange;
#endif
// 分组添加删除按钮
var groupAddContainer = root.Q("GroupAddContainer");
{
var addBtn = groupAddContainer.Q<Button>("AddBtn");
addBtn.clicked += AddGroupBtn_clicked;
var removeBtn = groupAddContainer.Q<Button>("RemoveBtn");
removeBtn.clicked += RemoveGroupBtn_clicked;
}
// 分组容器
_groupContainer = root.Q("GroupContainer");
// 分组名称
_groupNameTxt = root.Q<TextField>("GroupName");
_groupNameTxt.RegisterValueChangedCallback(evt =>
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup != null)
{
selectGroup.GroupName = evt.newValue;
AssetBundleCollectorSettingData.ModifyGroup(selectGroup);
}
});
// 分组备注
_groupDescTxt = root.Q<TextField>("GroupDesc");
_groupDescTxt.RegisterValueChangedCallback(evt =>
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup != null)
{
selectGroup.GroupDesc = evt.newValue;
AssetBundleCollectorSettingData.ModifyGroup(selectGroup);
}
});
// 分组的资源标签
_groupAssetTagsTxt = root.Q<TextField>("GroupAssetTags");
_groupAssetTagsTxt.RegisterValueChangedCallback(evt =>
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup != null)
{
selectGroup.AssetTags = evt.newValue;
AssetBundleCollectorSettingData.ModifyGroup(selectGroup);
}
});
// 收集列表相关
_collectorScrollView = root.Q<ScrollView>("CollectorScrollView");
_collectorScrollView.style.height = new Length(100, LengthUnit.Percent);
_collectorScrollView.viewDataKey = "scrollView";
// 收集器创建按钮
var collectorAddContainer = root.Q("CollectorAddContainer");
{
var addBtn = collectorAddContainer.Q<Button>("AddBtn");
addBtn.clicked += AddCollectorBtn_clicked;
}
// 刷新窗体
RefreshWindow();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
}
public void OnDestroy()
{
if (AssetBundleCollectorSettingData.IsDirty)
AssetBundleCollectorSettingData.SaveFile();
}
private void RefreshWindow()
{
_enableAddressableToogle.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.EnableAddressable);
_autoCollectShaderToogle.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.AutoCollectShaders);
_shaderBundleNameTxt.SetEnabled(AssetBundleCollectorSettingData.Setting.AutoCollectShaders);
_shaderBundleNameTxt.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.ShadersBundleName);
_groupContainer.visible = false;
FillGroupViewData();
}
private void ExportBtn_clicked()
{
string resultPath = EditorTools.OpenFolderPanel("Export XML", "Assets/");
if (resultPath != null)
{
AssetBundleCollectorConfig.ExportXmlConfig($"{resultPath}/{nameof(AssetBundleCollectorConfig)}.xml");
}
}
private void ImportBtn_clicked()
{
string resultPath = EditorTools.OpenFilePath("Import XML", "Assets/", "xml");
if (resultPath != null)
{
AssetBundleCollectorConfig.ImportXmlConfig(resultPath);
RefreshWindow();
}
}
// 分组列表相关
private void FillGroupViewData()
{
_groupListView.Clear();
_groupListView.ClearSelection();
_groupListView.itemsSource = AssetBundleCollectorSettingData.Setting.Groups;
_groupListView.Rebuild();
}
private VisualElement MakeGroupListViewItem()
{
VisualElement element = new VisualElement();
{
var label = new Label();
label.name = "Label1";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.flexGrow = 1f;
label.style.height = 20f;
element.Add(label);
}
return element;
}
private void BindGroupListViewItem(VisualElement element, int index)
{
var group = AssetBundleCollectorSettingData.Setting.Groups[index];
// Group Name
var textField1 = element.Q<Label>("Label1");
if (string.IsNullOrEmpty(group.GroupDesc))
textField1.text = group.GroupName;
else
textField1.text = $"{group.GroupName} ({group.GroupDesc})";
}
private void GroupListView_onSelectionChange(IEnumerable<object> objs)
{
FillCollectorViewData();
}
private void AddGroupBtn_clicked()
{
Undo.RecordObject(AssetBundleCollectorSettingData.Setting, "YooAsset AddGroup");
AssetBundleCollectorSettingData.CreateGroup("Default Group");
FillGroupViewData();
}
private void RemoveGroupBtn_clicked()
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup == null)
return;
Undo.RecordObject(AssetBundleCollectorSettingData.Setting, "YooAsset RemoveGroup");
AssetBundleCollectorSettingData.RemoveGroup(selectGroup);
FillGroupViewData();
}
// 收集列表相关
private void FillCollectorViewData()
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup == null)
{
_groupContainer.visible = false;
return;
}
_groupContainer.visible = true;
_groupNameTxt.SetValueWithoutNotify(selectGroup.GroupName);
_groupDescTxt.SetValueWithoutNotify(selectGroup.GroupDesc);
_groupAssetTagsTxt.SetValueWithoutNotify(selectGroup.AssetTags);
// 填充数据
_collectorScrollView.Clear();
for (int i = 0; i < selectGroup.Collectors.Count; i++)
{
VisualElement element = MakeCollectorListViewItem();
BindCollectorListViewItem(element, i);
_collectorScrollView.Add(element);
}
}
private VisualElement MakeCollectorListViewItem()
{
VisualElement element = new VisualElement();
VisualElement elementTop = new VisualElement();
elementTop.style.flexDirection = FlexDirection.Row;
element.Add(elementTop);
VisualElement elementBottom = new VisualElement();
elementBottom.style.flexDirection = FlexDirection.Row;
element.Add(elementBottom);
VisualElement elementFoldout = new VisualElement();
elementFoldout.style.flexDirection = FlexDirection.Row;
element.Add(elementFoldout);
VisualElement elementSpace = new VisualElement();
elementSpace.style.flexDirection = FlexDirection.Column;
element.Add(elementSpace);
// Top VisualElement
{
var button = new Button();
button.name = "Button1";
button.text = "-";
button.style.unityTextAlign = TextAnchor.MiddleCenter;
button.style.flexGrow = 0f;
elementTop.Add(button);
}
{
var objectField = new ObjectField();
objectField.name = "ObjectField1";
objectField.label = "Collector";
objectField.objectType = typeof(UnityEngine.Object);
objectField.style.unityTextAlign = TextAnchor.MiddleLeft;
objectField.style.flexGrow = 1f;
elementTop.Add(objectField);
var label = objectField.Q<Label>();
label.style.minWidth = 63;
}
// Bottom VisualElement
{
var label = new Label();
label.style.width = 90;
elementBottom.Add(label);
}
{
var popupField = new PopupField<string>(_collectorTypeList, 0);
popupField.name = "PopupField0";
popupField.style.unityTextAlign = TextAnchor.MiddleLeft;
popupField.style.width = 150;
elementBottom.Add(popupField);
}
if (_enableAddressableToogle.value)
{
var popupField = new PopupField<string>(_addressRuleList, 0);
popupField.name = "PopupField1";
popupField.style.unityTextAlign = TextAnchor.MiddleLeft;
popupField.style.width = 200;
elementBottom.Add(popupField);
}
{
var popupField = new PopupField<string>(_packRuleList, 0);
popupField.name = "PopupField2";
popupField.style.unityTextAlign = TextAnchor.MiddleLeft;
popupField.style.width = 150;
elementBottom.Add(popupField);
}
{
var popupField = new PopupField<string>(_filterRuleList, 0);
popupField.name = "PopupField3";
popupField.style.unityTextAlign = TextAnchor.MiddleLeft;
popupField.style.width = 150;
elementBottom.Add(popupField);
}
{
var textField = new TextField();
textField.name = "TextField1";
textField.label = "Tags";
textField.style.width = 100;
textField.style.marginLeft = 20;
textField.style.flexGrow = 1;
elementBottom.Add(textField);
var label = textField.Q<Label>();
label.style.minWidth = 40;
}
// Foldout VisualElement
{
var label = new Label();
label.style.width = 90;
elementFoldout.Add(label);
}
{
var foldout = new Foldout();
foldout.name = "Foldout1";
foldout.value = false;
foldout.text = "Main Assets";
elementFoldout.Add(foldout);
}
// Space VisualElement
{
var label = new Label();
label.style.height = 10;
elementSpace.Add(label);
}
return element;
}
private void BindCollectorListViewItem(VisualElement element, int index)
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup == null)
return;
var collector = selectGroup.Collectors[index];
var collectObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(collector.CollectPath);
if (collectObject != null)
collectObject.name = collector.CollectPath;
// Foldout
var foldout = element.Q<Foldout>("Foldout1");
foldout.RegisterValueChangedCallback(evt =>
{
if (evt.newValue)
RefreshFoldout(foldout, selectGroup, collector);
else
foldout.Clear();
});
// Remove Button
var removeBtn = element.Q<Button>("Button1");
removeBtn.clicked += () =>
{
RemoveCollectorBtn_clicked(collector);
};
// Collector Path
var objectField1 = element.Q<ObjectField>("ObjectField1");
objectField1.SetValueWithoutNotify(collectObject);
objectField1.RegisterValueChangedCallback(evt =>
{
collector.CollectPath = AssetDatabase.GetAssetPath(evt.newValue);
objectField1.value.name = collector.CollectPath;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
{
RefreshFoldout(foldout, selectGroup, collector);
}
});
// Collector Type
var popupField0 = element.Q<PopupField<string>>("PopupField0");
popupField0.index = GetCollectorTypeIndex(collector.CollectorType.ToString());
popupField0.RegisterValueChangedCallback(evt =>
{
collector.CollectorType = StringUtility.NameToEnum<ECollectorType>(evt.newValue);
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
{
RefreshFoldout(foldout, selectGroup, collector);
}
});
// Address Rule
var popupField1 = element.Q<PopupField<string>>("PopupField1");
if (popupField1 != null)
{
popupField1.index = GetAddressRuleIndex(collector.AddressRuleName);
popupField1.RegisterValueChangedCallback(evt =>
{
collector.AddressRuleName = evt.newValue;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
{
RefreshFoldout(foldout, selectGroup, collector);
}
});
}
// Pack Rule
var popupField2 = element.Q<PopupField<string>>("PopupField2");
popupField2.index = GetPackRuleIndex(collector.PackRuleName);
popupField2.RegisterValueChangedCallback(evt =>
{
collector.PackRuleName = evt.newValue;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
{
RefreshFoldout(foldout, selectGroup, collector);
}
});
// Filter Rule
var popupField3 = element.Q<PopupField<string>>("PopupField3");
popupField3.index = GetFilterRuleIndex(collector.FilterRuleName);
popupField3.RegisterValueChangedCallback(evt =>
{
collector.FilterRuleName = evt.newValue;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
{
RefreshFoldout(foldout, selectGroup, collector);
}
});
// Tags
var textFiled1 = element.Q<TextField>("TextField1");
textFiled1.SetValueWithoutNotify(collector.AssetTags);
textFiled1.RegisterValueChangedCallback(evt =>
{
collector.AssetTags = evt.newValue;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
});
}
private void RefreshFoldout(Foldout foldout, AssetBundleCollectorGroup group, AssetBundleCollector collector)
{
// 清空旧元素
foldout.Clear();
if (collector.IsValid() == false)
{
Debug.LogWarning($"The collector is invalid : {collector.CollectPath} in group : {group.GroupName}");
return;
}
if (collector.CollectorType == ECollectorType.MainAssetCollector || collector.CollectorType == ECollectorType.StaticAssetCollector)
{
List<CollectAssetInfo> collectAssetInfos = null;
try
{
collectAssetInfos = collector.GetAllCollectAssets(group);
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
if (collectAssetInfos != null)
{
foreach (var collectAssetInfo in collectAssetInfos)
{
VisualElement elementRow = new VisualElement();
elementRow.style.flexDirection = FlexDirection.Row;
foldout.Add(elementRow);
string showInfo = collectAssetInfo.AssetPath;
if (_enableAddressableToogle.value)
{
IAddressRule instance = AssetBundleCollectorSettingData.GetAddressRuleInstance(collector.AddressRuleName);
AddressRuleData ruleData = new AddressRuleData(collectAssetInfo.AssetPath, collector.CollectPath, group.GroupName);
string addressValue = instance.GetAssetAddress(ruleData);
showInfo = $"[{addressValue}] {showInfo}";
}
var label = new Label();
label.text = showInfo;
label.style.width = 300;
label.style.marginLeft = 0;
label.style.flexGrow = 1;
elementRow.Add(label);
}
}
}
}
private void AddCollectorBtn_clicked()
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup == null)
return;
AssetBundleCollectorSettingData.CreateCollector(selectGroup, string.Empty);
FillCollectorViewData();
}
private void RemoveCollectorBtn_clicked(AssetBundleCollector selectCollector)
{
var selectGroup = _groupListView.selectedItem as AssetBundleCollectorGroup;
if (selectGroup == null)
return;
if (selectCollector == null)
return;
AssetBundleCollectorSettingData.RemoveCollector(selectGroup, selectCollector);
FillCollectorViewData();
}
private int GetCollectorTypeIndex(string typeName)
{
for (int i = 0; i < _collectorTypeList.Count; i++)
{
if (_collectorTypeList[i] == typeName)
return i;
}
return 0;
}
private int GetAddressRuleIndex(string ruleName)
{
for (int i = 0; i < _addressRuleList.Count; i++)
{
if (_addressRuleList[i] == ruleName)
return i;
}
return 0;
}
private int GetPackRuleIndex(string ruleName)
{
for (int i = 0; i < _packRuleList.Count; i++)
{
if (_packRuleList[i] == ruleName)
return i;
}
return 0;
}
private int GetFilterRuleIndex(string ruleName)
{
for (int i = 0; i < _filterRuleList.Count; i++)
{
if (_filterRuleList[i] == ruleName)
return i;
}
return 0;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b730ebd685b28964a9f002593751e98a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row-reverse;">
<ui:Button text="导出" display-tooltip-when-elided="true" name="ExportButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
<ui:Button text="导入" display-tooltip-when-elided="true" name="ImportButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
</uie:Toolbar>
<ui:VisualElement name="ContentContainer" style="flex-grow: 1; flex-direction: row;">
<ui:VisualElement name="LeftContainer" style="width: 200px; flex-grow: 0; background-color: rgb(67, 67, 67); border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
<ui:ListView focusable="true" name="GroupListView" item-height="20" virtualization-method="DynamicHeight" style="flex-grow: 1;" />
<ui:VisualElement name="GroupAddContainer" style="height: 20px; flex-direction: row; justify-content: center;">
<ui:Button text=" - " display-tooltip-when-elided="true" name="RemoveBtn" />
<ui:Button text=" + " display-tooltip-when-elided="true" name="AddBtn" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="RightContainer" style="flex-direction: column; flex-grow: 1;">
<ui:VisualElement name="PublicContainer" style="height: 30px; background-color: rgb(67, 67, 67); flex-direction: row; border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
<ui:Toggle label="Enable Addressable" name="EnableAddressable" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Auto Collect Shaders" name="AutoCollectShader" style="width: 196px; -unity-text-align: middle-left;" />
<ui:TextField picking-mode="Ignore" label="Shader Bundle Name" name="ShaderBundleName" style="flex-grow: 1; -unity-text-align: middle-left;" />
</ui:VisualElement>
<ui:VisualElement name="GroupContainer" style="flex-grow: 1; border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
<ui:TextField picking-mode="Ignore" label="Group Name" name="GroupName" />
<ui:TextField picking-mode="Ignore" label="Group Desc" name="GroupDesc" />
<ui:TextField picking-mode="Ignore" label="Group Asset Tags" name="GroupAssetTags" />
<ui:VisualElement name="CollectorAddContainer" style="height: 20px; flex-direction: row-reverse;">
<ui:Button text="[ + ]" display-tooltip-when-elided="true" name="AddBtn" />
</ui:VisualElement>
<ui:ScrollView name="CollectorScrollView" style="flex-grow: 1;" />
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 355c4ac5cdebddc4c8362bed6f17a79e
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -0,0 +1,54 @@
using System.Collections;
using System.Collections.Generic;
namespace YooAsset.Editor
{
public class CollectAssetInfo
{
/// <summary>
/// 收集器类型
/// </summary>
public ECollectorType CollectorType { private set; get; }
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName { private set; get; }
/// <summary>
/// 可寻址地址
/// </summary>
public string Address { private set; get; }
/// <summary>
/// 资源路径
/// </summary>
public string AssetPath { private set; get; }
/// <summary>
/// 资源分类标签
/// </summary>
public List<string> AssetTags { private set; get; }
/// <summary>
/// 是否为原生资源
/// </summary>
public bool IsRawAsset { private set; get; }
/// <summary>
/// 依赖的资源列表
/// </summary>
public List<string> DependAssets = new List<string>();
public CollectAssetInfo(ECollectorType collectorType, string bundleName, string address, string assetPath, List<string> assetTags, bool isRawAsset)
{
CollectorType = collectorType;
BundleName = bundleName;
Address = address;
AssetPath = assetPath;
AssetTags = assetTags;
IsRawAsset = isRawAsset;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b44b2cc585bc59c4d879d1edac67f7c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
using System.IO;
namespace YooAsset.Editor
{
/// <summary>
/// 以文件名为定位地址
/// </summary>
public class AddressByFileName : IAddressRule
{
string IAddressRule.GetAssetAddress(AddressRuleData data)
{
return Path.GetFileNameWithoutExtension(data.AssetPath);
}
}
/// <summary>
/// 以组名+文件名为定位地址
/// </summary>
public class AddressByGroupAndFileName : IAddressRule
{
string IAddressRule.GetAssetAddress(AddressRuleData data)
{
string fileName = Path.GetFileNameWithoutExtension(data.AssetPath);
return $"{data.GroupName}_{fileName}";
}
}
/// <summary>
/// 以收集器名+文件名为定位地址
/// </summary>
public class AddressByCollectorAndFileName : IAddressRule
{
string IAddressRule.GetAssetAddress(AddressRuleData data)
{
string fileName = Path.GetFileNameWithoutExtension(data.AssetPath);
string collectorName = Path.GetFileNameWithoutExtension(data.CollectPath);
return $"{collectorName}_{fileName}";
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6df37bfd87103a54ca60c0c467a5f33b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
using UnityEngine;
using UnityEditor;
using System.IO;
namespace YooAsset.Editor
{
/// <summary>
/// 收集所有资源
/// </summary>
public class CollectAll : IFilterRule
{
public bool IsCollectAsset(FilterRuleData data)
{
return true;
}
}
/// <summary>
/// 只收集场景
/// </summary>
public class CollectScene : IFilterRule
{
public bool IsCollectAsset(FilterRuleData data)
{
return Path.GetExtension(data.AssetPath) == ".unity";
}
}
/// <summary>
/// 只收集预制体
/// </summary>
public class CollectPrefab : IFilterRule
{
public bool IsCollectAsset(FilterRuleData data)
{
return Path.GetExtension(data.AssetPath) == ".prefab";
}
}
/// <summary>
/// 只收集精灵类型的资源
/// </summary>
public class CollectSprite : IFilterRule
{
public bool IsCollectAsset(FilterRuleData data)
{
if (AssetDatabase.GetMainAssetTypeAtPath(data.AssetPath) == typeof(Sprite))
return true;
else
return false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a74c81d149472fb4c960a1db1fd8accc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,114 @@
using System;
using System.IO;
using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 以文件路径作为资源包名
/// 注意:每个文件独自打资源包
/// 例如:收集器路径为 "Assets/UIPanel"
/// 例如:"Assets/UIPanel/Shop/Image/backgroud.png" --> "assets/uipanel/shop/image/backgroud.bundle"
/// 例如:"Assets/UIPanel/Shop/View/main.prefab" --> "assets/uipanel/shop/view/main.bundle"
/// </summary>
public class PackSeparately : IPackRule
{
string IPackRule.GetBundleName(PackRuleData data)
{
return StringUtility.RemoveExtension(data.AssetPath);
}
}
/// <summary>
/// 以父类文件夹路径作为资源包名
/// 注意:文件夹下所有文件打进一个资源包
/// 例如:收集器路径为 "Assets/UIPanel"
/// 例如:"Assets/UIPanel/Shop/Image/backgroud.png" --> "assets/uipanel/shop/image.bundle"
/// 例如:"Assets/UIPanel/Shop/View/main.prefab" --> "assets/uipanel/shop/view.bundle"
/// </summary>
public class PackDirectory : IPackRule
{
string IPackRule.GetBundleName(PackRuleData data)
{
return Path.GetDirectoryName(data.AssetPath);
}
}
/// <summary>
/// 以收集器路径下顶级文件夹为资源包名
/// 注意:文件夹下所有文件打进一个资源包
/// 例如:收集器路径为 "Assets/UIPanel"
/// 例如:"Assets/UIPanel/Shop/Image/backgroud.png" --> "assets/uipanel/shop.bundle"
/// 例如:"Assets/UIPanel/Shop/View/main.prefab" --> "assets/uipanel/shop.bundle"
/// </summary>
public class PackTopDirectory : IPackRule
{
string IPackRule.GetBundleName(PackRuleData data)
{
string assetPath = data.AssetPath.Replace(data.CollectPath, string.Empty);
assetPath = assetPath.TrimStart('/');
string[] splits = assetPath.Split('/');
if (splits.Length > 0)
{
if (Path.HasExtension(splits[0]))
throw new Exception($"Not found root directory : {assetPath}");
string bundleName = $"{data.CollectPath}/{splits[0]}";
return bundleName;
}
else
{
throw new Exception($"Not found root directory : {assetPath}");
}
}
}
/// <summary>
/// 以收集器路径作为资源包名
/// 注意:收集的所有文件打进一个资源包
/// </summary>
public class PackCollector : IPackRule
{
string IPackRule.GetBundleName(PackRuleData data)
{
return StringUtility.RemoveExtension(data.CollectPath);
}
}
/// <summary>
/// 以分组名称作为资源包名
/// 注意:收集的所有文件打进一个资源包
/// </summary>
public class PackGroup : IPackRule
{
string IPackRule.GetBundleName(PackRuleData data)
{
return data.GroupName;
}
}
/// <summary>
/// 原生文件打包模式
/// 注意:原生文件打包支持:图片,音频,视频,文本
/// </summary>
public class PackRawFile : IPackRule
{
string IPackRule.GetBundleName(PackRuleData data)
{
string extension = StringUtility.RemoveFirstChar(Path.GetExtension(data.AssetPath));
if (extension == EAssetFileExtension.unity.ToString() || extension == EAssetFileExtension.prefab.ToString() ||
extension == EAssetFileExtension.mat.ToString() || extension == EAssetFileExtension.controller.ToString() ||
extension == EAssetFileExtension.fbx.ToString() || extension == EAssetFileExtension.anim.ToString() ||
extension == EAssetFileExtension.shader.ToString())
{
throw new Exception($"{nameof(PackRawFile)} is not support file estension : {extension}");
}
// 注意:原生文件只支持无依赖关系的资源
string[] depends = AssetDatabase.GetDependencies(data.AssetPath, true);
if (depends.Length != 1)
throw new Exception($"{nameof(PackRawFile)} is not support estension : {extension}");
return StringUtility.RemoveExtension(data.AssetPath);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a924dc0a22fc104781bf9aaadd60c29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using System;
namespace YooAsset.Editor
{
[Serializable]
public enum ECollectorType
{
/// <summary>
/// 收集参与打包的主资源对象,并写入到资源清单的资源列表里(可以通过代码加载)。
/// </summary>
MainAssetCollector,
/// <summary>
/// 收集参与打包的主资源对象,但不写入到资源清单的资源列表里(无法通过代码加载)。
/// </summary>
StaticAssetCollector,
/// <summary>
/// 收集参与打包的依赖资源对象,但不写入到资源清单的资源列表里(无法通过代码加载)。
/// 注意:如果依赖资源对象没有被主资源对象引用,则不参与打包构建。
/// </summary>
DependAssetCollector,
/// <summary>
/// 该收集器类型不能被设置
/// </summary>
None,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4bbef9cb5c1a40b41a28a65df3449abe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@

namespace YooAsset.Editor
{
public struct AddressRuleData
{
public string AssetPath;
public string CollectPath;
public string GroupName;
public AddressRuleData(string assetPath, string collectPath, string groupName)
{
AssetPath = assetPath;
CollectPath = collectPath;
GroupName = groupName;
}
}
/// <summary>
/// 寻址规则接口
/// </summary>
public interface IAddressRule
{
string GetAssetAddress(AddressRuleData data);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 426a4ff47699b6844946329f54a89128
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@

namespace YooAsset.Editor
{
public struct FilterRuleData
{
public string AssetPath;
public FilterRuleData(string assetPath)
{
AssetPath = assetPath;
}
}
/// <summary>
/// 资源过滤规则接口
/// </summary>
public interface IFilterRule
{
/// <summary>
/// 是否为收集资源
/// </summary>
/// <returns>如果收集该资源返回TRUE</returns>
bool IsCollectAsset(FilterRuleData data);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffe1385deb0bd9844a514f1c2fd65e62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@

namespace YooAsset.Editor
{
public struct PackRuleData
{
public string AssetPath;
public string CollectPath;
public string GroupName;
public PackRuleData(string assetPath)
{
AssetPath = assetPath;
CollectPath = string.Empty;
GroupName = string.Empty;
}
public PackRuleData(string assetPath, string collectPath, string groupName)
{
AssetPath = assetPath;
CollectPath = collectPath;
GroupName = groupName;
}
}
/// <summary>
/// 资源打包规则接口
/// </summary>
public interface IPackRule
{
/// <summary>
/// 获取资源打包所属的资源包名称
/// </summary>
string GetBundleName(PackRuleData data);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 577f7c1abcdf0a140958f1d1d44d6f40
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: