mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-06-29 09:53:57 +00:00
Compare commits
8 Commits
3.0.2-beta
...
d39d9b59ef
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d39d9b59ef | ||
|
|
31c09d53bb | ||
|
|
a6299268d3 | ||
|
|
89b516942e | ||
|
|
8c49c27264 | ||
|
|
51c8c00604 | ||
|
|
cb96767f2d | ||
|
|
55d98dde02 |
@@ -175,6 +175,17 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 工程中是否已存在收集器配置文件
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>存在返回 true</returns>
|
||||||
|
public static bool HasSettingAsset()
|
||||||
|
{
|
||||||
|
string typeName = nameof(BundleCollectorSetting);
|
||||||
|
var guids = AssetDatabase.FindAssets($"t:{typeName}");
|
||||||
|
return guids != null && guids.Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储配置文件
|
/// 存储配置文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -19,10 +19,30 @@ namespace YooAsset.Editor
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[MenuItem("YooAsset/Bundle Collector", false, 101)]
|
[MenuItem("YooAsset/Bundle Collector", false, 101)]
|
||||||
public static void OpenWindow()
|
public static void OpenWindow()
|
||||||
|
{
|
||||||
|
OpenWindowInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开资源收集器窗口并定位到指定的收集器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="packageName">包裹名称</param>
|
||||||
|
/// <param name="groupName">分组名称</param>
|
||||||
|
/// <param name="collectPath">收集路径</param>
|
||||||
|
public static void OpenWindow(string packageName, string groupName, string collectPath)
|
||||||
|
{
|
||||||
|
BundleCollectorWindow window = OpenWindowInternal();
|
||||||
|
window.SetFocusCollector(packageName, groupName, collectPath);
|
||||||
|
window.RefreshWindow();
|
||||||
|
window.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BundleCollectorWindow OpenWindowInternal()
|
||||||
{
|
{
|
||||||
Type[] dockedTypes = EditorWindowDefine.GetDockedWindowTypes();
|
Type[] dockedTypes = EditorWindowDefine.GetDockedWindowTypes();
|
||||||
BundleCollectorWindow window = GetWindow<BundleCollectorWindow>("Bundle Collector", true, dockedTypes);
|
BundleCollectorWindow window = GetWindow<BundleCollectorWindow>("Bundle Collector", true, dockedTypes);
|
||||||
window.minSize = new Vector2(800, 600);
|
window.minSize = new Vector2(800, 600);
|
||||||
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string PlaceholderClass = "search-placeholder";
|
private const string PlaceholderClass = "search-placeholder";
|
||||||
@@ -77,6 +97,7 @@ namespace YooAsset.Editor
|
|||||||
private int _highlightCollectorIndex = -1;
|
private int _highlightCollectorIndex = -1;
|
||||||
private int _lastModifyPackageIndex = 0;
|
private int _lastModifyPackageIndex = 0;
|
||||||
private int _lastModifyGroupIndex = 0;
|
private int _lastModifyGroupIndex = 0;
|
||||||
|
private bool _hasFocusCollector = false;
|
||||||
private bool _showGlobalSettings = false;
|
private bool _showGlobalSettings = false;
|
||||||
private bool _showPackageSettings = false;
|
private bool _showPackageSettings = false;
|
||||||
|
|
||||||
@@ -471,6 +492,7 @@ namespace YooAsset.Editor
|
|||||||
private void RefreshWindow()
|
private void RefreshWindow()
|
||||||
{
|
{
|
||||||
_highlightAssetPath = null;
|
_highlightAssetPath = null;
|
||||||
|
if (_hasFocusCollector == false)
|
||||||
_highlightCollectorIndex = -1;
|
_highlightCollectorIndex = -1;
|
||||||
_groupContainer.visible = false;
|
_groupContainer.visible = false;
|
||||||
_collectorContainer.visible = false;
|
_collectorContainer.visible = false;
|
||||||
@@ -508,6 +530,7 @@ namespace YooAsset.Editor
|
|||||||
{
|
{
|
||||||
_highlightAssetPath = null;
|
_highlightAssetPath = null;
|
||||||
_highlightCollectorIndex = -1;
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
FillCollectorViewData();
|
FillCollectorViewData();
|
||||||
|
|
||||||
string searchInput = GetSearchInput();
|
string searchInput = GetSearchInput();
|
||||||
@@ -577,6 +600,46 @@ namespace YooAsset.Editor
|
|||||||
return ruleDisplayName.ClassName;
|
return ruleDisplayName.ClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 焦点相关
|
||||||
|
private void SetFocusCollector(string packageName, string groupName, string collectPath)
|
||||||
|
{
|
||||||
|
var packages = BundleCollectorSettingData.Setting.Packages;
|
||||||
|
int packageIndex = packages.FindIndex(item => item.PackageName == packageName);
|
||||||
|
if (packageIndex < 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Package not found: '{packageName}'.");
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var package = packages[packageIndex];
|
||||||
|
int groupIndex = package.Groups.FindIndex(item => item.GroupName == groupName);
|
||||||
|
if (groupIndex < 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Group not found: '{groupName}' in package '{packageName}'.");
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var group = package.Groups[groupIndex];
|
||||||
|
int collectorIndex = group.Collectors.FindIndex(item => string.Equals(item.CollectPath, collectPath, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (collectorIndex < 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Collector not found: '{collectPath}'.");
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_highlightAssetPath = null;
|
||||||
|
_highlightCollectorIndex = collectorIndex;
|
||||||
|
_lastModifyPackageIndex = packageIndex;
|
||||||
|
_lastModifyGroupIndex = groupIndex;
|
||||||
|
_hasFocusCollector = true;
|
||||||
|
}
|
||||||
|
|
||||||
// 搜索栏相关
|
// 搜索栏相关
|
||||||
private void ShowSearchResult(string message, Color color)
|
private void ShowSearchResult(string message, Color color)
|
||||||
{
|
{
|
||||||
@@ -898,6 +961,7 @@ namespace YooAsset.Editor
|
|||||||
if (foldout != null)
|
if (foldout != null)
|
||||||
foldout.value = true;
|
foldout.value = true;
|
||||||
_highlightCollectorIndex = -1;
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private VisualElement MakeCollectorListViewItem()
|
private VisualElement MakeCollectorListViewItem()
|
||||||
|
|||||||
@@ -161,17 +161,18 @@ namespace YooAsset
|
|||||||
/// <returns>缓存文件根目录的绝对路径</returns>
|
/// <returns>缓存文件根目录的绝对路径</returns>
|
||||||
internal static string GetEditorCacheRoot()
|
internal static string GetEditorCacheRoot()
|
||||||
{
|
{
|
||||||
// 注意:为了方便调试查看,编辑器下把存储目录放到项目根目录下。
|
// 注意:为了方便调试查看,编辑器下把存储目录放到项目的 Library 目录下。
|
||||||
string projectPath = Path.GetDirectoryName(Application.dataPath);
|
string projectPath = Path.GetDirectoryName(Application.dataPath);
|
||||||
if (string.IsNullOrEmpty(projectPath))
|
if (string.IsNullOrEmpty(projectPath))
|
||||||
throw new InvalidOperationException("Could not determine project root path from Application.dataPath.");
|
throw new InvalidOperationException("Could not determine project root path from Application.dataPath.");
|
||||||
projectPath = PathUtility.NormalizePath(projectPath);
|
projectPath = PathUtility.NormalizePath(projectPath);
|
||||||
|
|
||||||
|
string libraryPath = PathUtility.Combine(projectPath, "Library");
|
||||||
var settings = GetSettings();
|
var settings = GetSettings();
|
||||||
if (string.IsNullOrEmpty(settings.YooFolderName))
|
if (string.IsNullOrEmpty(settings.YooFolderName))
|
||||||
return projectPath;
|
return libraryPath;
|
||||||
else
|
else
|
||||||
return PathUtility.Combine(projectPath, settings.YooFolderName);
|
return PathUtility.Combine(libraryPath, settings.YooFolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
[CustomPropertyDrawer(typeof(GameObjectReference))]
|
[CustomPropertyDrawer(typeof(AssetReference), true)]
|
||||||
public class GameObjectReferenceDrawer : PropertyDrawer
|
public class AssetReferenceDrawer : PropertyDrawer
|
||||||
{
|
{
|
||||||
private const float LineSpacing = 2f;
|
private const float LineSpacing = 2f;
|
||||||
|
|
||||||
|
private Type _assetType;
|
||||||
|
|
||||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||||
{
|
{
|
||||||
SerializedProperty packageNameProp = property.FindPropertyRelative("_packageName");
|
SerializedProperty packageNameProp = property.FindPropertyRelative("_packageName");
|
||||||
SerializedProperty assetGUIDProp = property.FindPropertyRelative("_assetGUID");
|
SerializedProperty assetGUIDProp = property.FindPropertyRelative("_assetGUID");
|
||||||
|
|
||||||
|
Type assetType = GetAssetType();
|
||||||
|
|
||||||
EditorGUI.BeginProperty(position, label, property);
|
EditorGUI.BeginProperty(position, label, property);
|
||||||
{
|
{
|
||||||
float lineHeight = EditorGUIUtility.singleLineHeight;
|
float lineHeight = EditorGUIUtility.singleLineHeight;
|
||||||
@@ -19,19 +25,19 @@ public class GameObjectReferenceDrawer : PropertyDrawer
|
|||||||
// 绘制 PackageName
|
// 绘制 PackageName
|
||||||
packageNameProp.stringValue = EditorGUI.TextField(line, "Package Name", packageNameProp.stringValue);
|
packageNameProp.stringValue = EditorGUI.TextField(line, "Package Name", packageNameProp.stringValue);
|
||||||
|
|
||||||
// 加载 GameObject
|
// 加载当前资源对象
|
||||||
string assetGUID = assetGUIDProp.stringValue;
|
string assetGUID = assetGUIDProp.stringValue;
|
||||||
GameObject current = null;
|
UnityEngine.Object current = null;
|
||||||
if (string.IsNullOrEmpty(assetGUID) == false)
|
if (string.IsNullOrEmpty(assetGUID) == false)
|
||||||
{
|
{
|
||||||
string assetPath = AssetDatabase.GUIDToAssetPath(assetGUID);
|
string assetPath = AssetDatabase.GUIDToAssetPath(assetGUID);
|
||||||
if (string.IsNullOrEmpty(assetPath) == false)
|
if (string.IsNullOrEmpty(assetPath) == false)
|
||||||
current = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
|
current = AssetDatabase.LoadAssetAtPath(assetPath, assetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制 GameObject
|
// 绘制资源对象字段
|
||||||
line.y += lineHeight + LineSpacing;
|
line.y += lineHeight + LineSpacing;
|
||||||
GameObject newAsset = (GameObject)EditorGUI.ObjectField(line, "Game Object", current, typeof(GameObject), false);
|
UnityEngine.Object newAsset = EditorGUI.ObjectField(line, assetType.Name, current, assetType, false);
|
||||||
if (newAsset != current)
|
if (newAsset != current)
|
||||||
{
|
{
|
||||||
if (newAsset == null)
|
if (newAsset == null)
|
||||||
@@ -46,7 +52,7 @@ public class GameObjectReferenceDrawer : PropertyDrawer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制 AssetGUID
|
// 绘制 AssetGUID(只读)
|
||||||
line.y += lineHeight + LineSpacing;
|
line.y += lineHeight + LineSpacing;
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
EditorGUI.BeginDisabledGroup(true);
|
||||||
EditorGUI.TextField(line, "Asset GUID", assetGUIDProp.stringValue);
|
EditorGUI.TextField(line, "Asset GUID", assetGUIDProp.stringValue);
|
||||||
@@ -54,8 +60,31 @@ public class GameObjectReferenceDrawer : PropertyDrawer
|
|||||||
}
|
}
|
||||||
EditorGUI.EndProperty();
|
EditorGUI.EndProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||||
{
|
{
|
||||||
return EditorGUIUtility.singleLineHeight * 3 + LineSpacing * 2;
|
return EditorGUIUtility.singleLineHeight * 3 + LineSpacing * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通过反射获取字段对应子类的 AssetType
|
||||||
|
/// </summary>
|
||||||
|
private Type GetAssetType()
|
||||||
|
{
|
||||||
|
if (_assetType != null)
|
||||||
|
return _assetType;
|
||||||
|
|
||||||
|
Type fieldType = fieldInfo.FieldType;
|
||||||
|
|
||||||
|
// 兼容数组
|
||||||
|
if (fieldType.IsArray)
|
||||||
|
fieldType = fieldType.GetElementType();
|
||||||
|
// 兼容 List<T>
|
||||||
|
else if (fieldType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(fieldType))
|
||||||
|
fieldType = fieldType.GetGenericArguments()[0];
|
||||||
|
|
||||||
|
var instance = (AssetReference)Activator.CreateInstance(fieldType);
|
||||||
|
_assetType = instance.AssetType;
|
||||||
|
return _assetType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 53eb285fc3a7b614089a000f8c9c738c
|
guid: ee2a8d68b06fc434c8d70a9e1d94caf6
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dd8a9e643275082438da0f2f5c4f7f68
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace YooAsset.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 扩展的 IMGUI 绘制辅助方法集合
|
||||||
|
/// </summary>
|
||||||
|
internal static class BundleCollectorGUIDraw
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制区块标题
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">标题文本</param>
|
||||||
|
public static void DrawSectionTitle(string title)
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField(title, BundleCollectorGUIStyle.TitleStyle);
|
||||||
|
EditorGUILayout.Space(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制一个带字段名的只读文本字段
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="label">字段名</param>
|
||||||
|
/// <param name="value">字段值</param>
|
||||||
|
/// <param name="disabled">是否置灰整行</param>
|
||||||
|
public static void DrawLabelField(string label, string value, bool disabled = false)
|
||||||
|
{
|
||||||
|
using (new EditorGUI.DisabledScope(disabled))
|
||||||
|
{
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
GUILayout.Label(label, BundleCollectorGUIStyle.FieldLabelStyle, GUILayout.Width(EditorGUIUtility.labelWidth));
|
||||||
|
EditorGUILayout.LabelField(string.IsNullOrEmpty(value) ? "-" : value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制一个带字段名的延迟文本输入框
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="label">字段名</param>
|
||||||
|
/// <param name="value">当前文本值</param>
|
||||||
|
/// <returns>新的文本值</returns>
|
||||||
|
public static string DrawTextField(string label, string value)
|
||||||
|
{
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
GUILayout.Label(label, BundleCollectorGUIStyle.FieldLabelStyle, GUILayout.Width(EditorGUIUtility.labelWidth));
|
||||||
|
return EditorGUILayout.DelayedTextField(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制一个带字段名的下拉框
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="label">字段名</param>
|
||||||
|
/// <param name="index">当前选项索引</param>
|
||||||
|
/// <param name="displayedOptions">下拉选项</param>
|
||||||
|
/// <returns>新的选项索引</returns>
|
||||||
|
public static int DrawPopupField(string label, int index, string[] displayedOptions)
|
||||||
|
{
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
GUILayout.Label(label, BundleCollectorGUIStyle.FieldLabelStyle, GUILayout.Width(EditorGUIUtility.labelWidth));
|
||||||
|
return EditorGUILayout.Popup(index, displayedOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制规则选择行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="label">字段标签</param>
|
||||||
|
/// <param name="displayNames">显示名称列表</param>
|
||||||
|
/// <param name="currentIndex">当前选中索引</param>
|
||||||
|
/// <param name="newIndex">新选中的索引</param>
|
||||||
|
/// <returns>规则索引发生变化返回 true</returns>
|
||||||
|
public static bool TryDrawRuleSelection(string label, string[] displayNames, int currentIndex, out int newIndex)
|
||||||
|
{
|
||||||
|
newIndex = -1;
|
||||||
|
if (displayNames == null || displayNames.Length == 0)
|
||||||
|
{
|
||||||
|
using (new EditorGUI.DisabledScope(true)) DrawPopupField(label, 0, new[] { "<None>" });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentIndex = Mathf.Clamp(currentIndex, 0, displayNames.Length - 1);
|
||||||
|
newIndex = DrawPopupField(label, currentIndex, displayNames);
|
||||||
|
return newIndex != currentIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 15552077c0d6ff441a4cd62af62b7d5a
|
guid: fb2a2401e7c68a64496c3194543aff6b
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace YooAsset.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 扩展的 IMGUI 样式集合
|
||||||
|
/// </summary>
|
||||||
|
internal static class BundleCollectorGUIStyle
|
||||||
|
{
|
||||||
|
// 注意:GUIStyle 依赖 GUI 皮肤,不能在静态构造里创建,需延迟到绘制时初始化。
|
||||||
|
private static GUIStyle _titleStyle;
|
||||||
|
private static GUIStyle _fieldLabelStyle;
|
||||||
|
private static GUIStyle _sectionStyle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 区块标题样式:保持正文字号,仅通过加粗和间距与内容区分。
|
||||||
|
/// </summary>
|
||||||
|
public static GUIStyle TitleStyle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_titleStyle == null)
|
||||||
|
{
|
||||||
|
_titleStyle = new GUIStyle(EditorStyles.boldLabel)
|
||||||
|
{
|
||||||
|
fontStyle = FontStyle.Bold,
|
||||||
|
margin = new RectOffset(0, 0, 2, 4),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return _titleStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 字段名样式:保持正文字号。
|
||||||
|
/// </summary>
|
||||||
|
public static GUIStyle FieldLabelStyle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_fieldLabelStyle == null)
|
||||||
|
{
|
||||||
|
_fieldLabelStyle = new GUIStyle(EditorStyles.label)
|
||||||
|
{
|
||||||
|
fontStyle = FontStyle.Normal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return _fieldLabelStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分组卡片样式:基于 helpBox 增加内边距,让内容不贴边。
|
||||||
|
/// </summary>
|
||||||
|
public static GUIStyle SectionStyle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_sectionStyle == null)
|
||||||
|
{
|
||||||
|
_sectionStyle = new GUIStyle(EditorStyles.helpBox)
|
||||||
|
{
|
||||||
|
padding = new RectOffset(6, 6, 5, 6),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return _sectionStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8f37650836ac1ca4ab53da11208bace4
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,456 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace YooAsset.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 资源收集器的 Inspector 扩展
|
||||||
|
/// </summary>
|
||||||
|
[InitializeOnLoad]
|
||||||
|
internal static class BundleCollectorInspector
|
||||||
|
{
|
||||||
|
private struct CollectorContext
|
||||||
|
{
|
||||||
|
public BundleCollectorPackage Package;
|
||||||
|
public BundleCollectorGroup Group;
|
||||||
|
public BundleCollector Collector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string[] CollectorTypeNames =
|
||||||
|
{
|
||||||
|
nameof(ECollectorType.MainAssetCollector),
|
||||||
|
nameof(ECollectorType.StaticAssetCollector),
|
||||||
|
nameof(ECollectorType.DependAssetCollector),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int _createPackageIndex;
|
||||||
|
private static int _createGroupIndex;
|
||||||
|
|
||||||
|
static BundleCollectorInspector()
|
||||||
|
{
|
||||||
|
UnityEditor.Editor.finishedDefaultHeaderGUI -= OnPostHeaderGUI;
|
||||||
|
UnityEditor.Editor.finishedDefaultHeaderGUI += OnPostHeaderGUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inspector 默认头部绘制完成后的回调
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="editor">当前正在绘制的 Inspector 编辑器实例</param>
|
||||||
|
private static void OnPostHeaderGUI(UnityEditor.Editor editor)
|
||||||
|
{
|
||||||
|
// 注意:多目标选择的时候不绘制
|
||||||
|
if (editor.targets != null && editor.targets.Length > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UnityEngine.Object target = editor.target;
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 检测选择的路径是否合法
|
||||||
|
string assetPath = AssetDatabase.GetAssetPath(target);
|
||||||
|
if (string.IsNullOrEmpty(assetPath))
|
||||||
|
return;
|
||||||
|
if (assetPath == "Assets")
|
||||||
|
return;
|
||||||
|
if (assetPath.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) == false)
|
||||||
|
return;
|
||||||
|
if (AssetDatabase.IsValidFolder(assetPath) == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 检测配置文件是否存在
|
||||||
|
if (BundleCollectorSettingData.HasSettingAsset() == false)
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
EditorGUILayout.LabelField("YooAsset", "BundleCollectorSetting.asset not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据当前文件夹是否已经配置,动态切换展示模式。
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle))
|
||||||
|
{
|
||||||
|
bool isFindCollector = TryGetCollector(assetPath, out CollectorContext collectorContext);
|
||||||
|
if (isFindCollector)
|
||||||
|
{
|
||||||
|
DrawOpenCollectorHeader(collectorContext);
|
||||||
|
DrawTargetCollectorContent(collectorContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawCreateCollectorHeader(assetPath);
|
||||||
|
DrawCreateCollectorSelector();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void DrawCreateCollectorHeader(string assetPath)
|
||||||
|
{
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("YooAsset", EditorStyles.boldLabel, GUILayout.Width(95));
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
bool hasCreateTarget = TryGetCreateCollectorTarget(out var package, out var group);
|
||||||
|
using (new EditorGUI.DisabledScope(hasCreateTarget == false))
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("Create Collector", GUILayout.Width(120)))
|
||||||
|
{
|
||||||
|
TryAddCollector(assetPath, package, group, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void DrawCreateCollectorSelector()
|
||||||
|
{
|
||||||
|
using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle))
|
||||||
|
{
|
||||||
|
BundleCollectorGUIDraw.DrawSectionTitle("Package & Group");
|
||||||
|
|
||||||
|
var setting = BundleCollectorSettingData.Setting;
|
||||||
|
if (setting == null || setting.Packages.Count == 0)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("Please create a Package in the Bundle Collector window first.", MessageType.Info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClampCreateTargetIndices();
|
||||||
|
string[] packageNames = setting.Packages.Select(item => item.PackageName).ToArray();
|
||||||
|
int newPackageIndex = BundleCollectorGUIDraw.DrawPopupField("Package", _createPackageIndex, packageNames);
|
||||||
|
if (newPackageIndex != _createPackageIndex)
|
||||||
|
{
|
||||||
|
_createPackageIndex = newPackageIndex;
|
||||||
|
_createGroupIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var package = setting.Packages[_createPackageIndex];
|
||||||
|
if (package.Groups.Count == 0)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("Please create a Group in the Bundle Collector window first.", MessageType.Info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] groupNames = package.Groups.Select(item => item.GroupName).ToArray();
|
||||||
|
_createGroupIndex = BundleCollectorGUIDraw.DrawPopupField("Group", _createGroupIndex, groupNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void DrawOpenCollectorHeader(CollectorContext collectorContext)
|
||||||
|
{
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("YooAsset", EditorStyles.boldLabel, GUILayout.Width(95));
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Open Collector", GUILayout.Width(120)))
|
||||||
|
{
|
||||||
|
BundleCollectorWindow.OpenWindow(collectorContext.Package.PackageName, collectorContext.Group.GroupName, collectorContext.Collector.CollectPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void DrawTargetCollectorContent(CollectorContext collectorContext)
|
||||||
|
{
|
||||||
|
var package = collectorContext.Package;
|
||||||
|
var group = collectorContext.Group;
|
||||||
|
var collector = collectorContext.Collector;
|
||||||
|
var setting = BundleCollectorSettingData.Setting;
|
||||||
|
bool showAlias = setting.ShowEditorAlias;
|
||||||
|
|
||||||
|
float oldLabelWidth = EditorGUIUtility.labelWidth;
|
||||||
|
EditorGUIUtility.labelWidth = 100;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 区块:包裹与分组
|
||||||
|
using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle))
|
||||||
|
{
|
||||||
|
BundleCollectorGUIDraw.DrawSectionTitle("Package & Group");
|
||||||
|
|
||||||
|
// 包裹
|
||||||
|
var packageNames = setting.Packages.Select(p => p.PackageName).ToArray();
|
||||||
|
int packageIndex = Mathf.Max(0, Array.IndexOf(packageNames, package.PackageName));
|
||||||
|
int newPackageIndex = BundleCollectorGUIDraw.DrawPopupField("Package", packageIndex, packageNames);
|
||||||
|
if (newPackageIndex != packageIndex && MoveCollectorToPackage(collector, group, setting.Packages[newPackageIndex]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 分组
|
||||||
|
var groupNames = package.Groups.Select(g => g.GroupName).ToArray();
|
||||||
|
int groupIndex = Mathf.Max(0, Array.IndexOf(groupNames, group.GroupName));
|
||||||
|
int newGroupIndex = BundleCollectorGUIDraw.DrawPopupField("Group", groupIndex, groupNames);
|
||||||
|
if (newGroupIndex != groupIndex)
|
||||||
|
{
|
||||||
|
MoveCollectorToGroup(collector, group, package.Groups[newGroupIndex]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 区块:收集器配置
|
||||||
|
using (new EditorGUILayout.VerticalScope(BundleCollectorGUIStyle.SectionStyle))
|
||||||
|
{
|
||||||
|
BundleCollectorGUIDraw.DrawSectionTitle("Collector Settings");
|
||||||
|
BundleCollectorGUIDraw.DrawLabelField("Collect Path", collector.CollectPath);
|
||||||
|
|
||||||
|
// 收集器类型
|
||||||
|
int typeIndex = Mathf.Max(0, Array.IndexOf(CollectorTypeNames, collector.CollectorType.ToString()));
|
||||||
|
int newTypeIndex = BundleCollectorGUIDraw.DrawPopupField("Collector Type", typeIndex, CollectorTypeNames);
|
||||||
|
if (newTypeIndex != typeIndex)
|
||||||
|
{
|
||||||
|
RecordUndo("YooAsset.Inspector Modify CollectorType");
|
||||||
|
collector.CollectorType = EditorStringUtility.ParseEnum<ECollectorType>(CollectorTypeNames[newTypeIndex]);
|
||||||
|
CommitModify(group, collector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地址规则(仅对主资源收集器生效)
|
||||||
|
bool isMainCollector = collector.CollectorType == ECollectorType.MainAssetCollector;
|
||||||
|
using (new EditorGUI.DisabledScope(isMainCollector == false))
|
||||||
|
{
|
||||||
|
var addressRules = BundleCollectorSettingData.GetAddressRuleNames();
|
||||||
|
if (BundleCollectorGUIDraw.TryDrawRuleSelection("Address Rule", GetRuleDisplayNames(addressRules, showAlias), GetRuleIndex(addressRules, collector.AddressRuleName), out int newAddressRuleIndex))
|
||||||
|
{
|
||||||
|
RecordUndo("YooAsset.Inspector Modify AddressRule");
|
||||||
|
collector.AddressRuleName = addressRules[newAddressRuleIndex].ClassName;
|
||||||
|
CommitModify(group, collector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打包规则
|
||||||
|
var packRules = BundleCollectorSettingData.GetBundlePackRuleNames();
|
||||||
|
if (BundleCollectorGUIDraw.TryDrawRuleSelection("Pack Rule", GetRuleDisplayNames(packRules, showAlias), GetRuleIndex(packRules, collector.PackRuleName), out int newPackRuleIndex))
|
||||||
|
{
|
||||||
|
RecordUndo("YooAsset.Inspector Modify PackRule");
|
||||||
|
collector.PackRuleName = packRules[newPackRuleIndex].ClassName;
|
||||||
|
CommitModify(group, collector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤规则
|
||||||
|
var filterRules = BundleCollectorSettingData.GetAssetFilterRuleNames();
|
||||||
|
if (BundleCollectorGUIDraw.TryDrawRuleSelection("Filter Rule", GetRuleDisplayNames(filterRules, showAlias), GetRuleIndex(filterRules, collector.FilterRuleName), out int newFilterRuleIndex))
|
||||||
|
{
|
||||||
|
RecordUndo("YooAsset.Inspector Modify FilterRule");
|
||||||
|
collector.FilterRuleName = filterRules[newFilterRuleIndex].ClassName;
|
||||||
|
CommitModify(group, collector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户数据(延迟提交,避免逐键写盘)
|
||||||
|
string newUserData = BundleCollectorGUIDraw.DrawTextField("UserData", collector.UserData);
|
||||||
|
if (newUserData != collector.UserData)
|
||||||
|
{
|
||||||
|
RecordUndo("YooAsset.Inspector Modify UserData");
|
||||||
|
collector.UserData = newUserData;
|
||||||
|
CommitModify(group, collector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 资源标签(仅对主资源收集器生效)
|
||||||
|
using (new EditorGUI.DisabledScope(isMainCollector == false))
|
||||||
|
{
|
||||||
|
string newTags = BundleCollectorGUIDraw.DrawTextField("Tags", collector.AssetTags);
|
||||||
|
if (newTags != collector.AssetTags)
|
||||||
|
{
|
||||||
|
RecordUndo("YooAsset.Inspector Modify AssetTags");
|
||||||
|
collector.AssetTags = newTags;
|
||||||
|
CommitModify(group, collector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
EditorGUIUtility.labelWidth = oldLabelWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取规则列表用于下拉框展示的名称数组
|
||||||
|
/// </summary>
|
||||||
|
private static string[] GetRuleDisplayNames(List<RuleDisplayName> rules, bool showAlias)
|
||||||
|
{
|
||||||
|
if (rules == null || rules.Count == 0)
|
||||||
|
return Array.Empty<string>();
|
||||||
|
|
||||||
|
return rules.Select(rule => showAlias ? rule.DisplayName : rule.ClassName).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据规则类名查找规则在列表中的索引
|
||||||
|
/// </summary>
|
||||||
|
private static int GetRuleIndex(List<RuleDisplayName> rules, string className)
|
||||||
|
{
|
||||||
|
if (rules == null || rules.Count == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return Mathf.Max(0, rules.FindIndex(rule => rule.ClassName == className));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 数据查找与编辑
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前创建收集器所选择的目标包裹和分组
|
||||||
|
/// </summary>
|
||||||
|
private static bool TryGetCreateCollectorTarget(out BundleCollectorPackage package, out BundleCollectorGroup group)
|
||||||
|
{
|
||||||
|
package = null;
|
||||||
|
group = null;
|
||||||
|
|
||||||
|
var setting = BundleCollectorSettingData.Setting;
|
||||||
|
if (setting == null || setting.Packages.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ClampCreateTargetIndices();
|
||||||
|
package = setting.Packages[_createPackageIndex];
|
||||||
|
if (package.Groups.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
group = package.Groups[_createGroupIndex];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将创建目标的包裹/分组索引收敛到当前配置的合法范围
|
||||||
|
/// </summary>
|
||||||
|
private static void ClampCreateTargetIndices()
|
||||||
|
{
|
||||||
|
var setting = BundleCollectorSettingData.Setting;
|
||||||
|
if (setting == null || setting.Packages.Count == 0)
|
||||||
|
{
|
||||||
|
_createPackageIndex = 0;
|
||||||
|
_createGroupIndex = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createPackageIndex = Mathf.Clamp(_createPackageIndex, 0, setting.Packages.Count - 1);
|
||||||
|
var package = setting.Packages[_createPackageIndex];
|
||||||
|
if (package.Groups.Count == 0)
|
||||||
|
{
|
||||||
|
_createGroupIndex = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createGroupIndex = Mathf.Clamp(_createGroupIndex, 0, package.Groups.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按文件夹路径精确获取已配置的收集器信息
|
||||||
|
/// </summary>
|
||||||
|
private static bool TryGetCollector(string folderPath, out CollectorContext result)
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
|
||||||
|
var setting = BundleCollectorSettingData.Setting;
|
||||||
|
if (setting == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var package in setting.Packages)
|
||||||
|
{
|
||||||
|
foreach (var group in package.Groups)
|
||||||
|
{
|
||||||
|
foreach (var collector in group.Collectors)
|
||||||
|
{
|
||||||
|
if (string.Equals(collector.CollectPath, folderPath, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result = new CollectorContext
|
||||||
|
{
|
||||||
|
Package = package,
|
||||||
|
Group = group,
|
||||||
|
Collector = collector,
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为指定文件夹在目标包裹分组下创建收集器
|
||||||
|
/// </summary>
|
||||||
|
private static bool TryAddCollector(string folderPath, BundleCollectorPackage package, BundleCollectorGroup group, out CollectorContext result)
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
if (package == null || group == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RecordUndo("YooAsset.Inspector Add Collector");
|
||||||
|
var collector = new BundleCollector
|
||||||
|
{
|
||||||
|
CollectPath = folderPath,
|
||||||
|
CollectorGUID = AssetDatabase.AssetPathToGUID(folderPath),
|
||||||
|
};
|
||||||
|
BundleCollectorSettingData.CreateCollector(group, collector);
|
||||||
|
BundleCollectorSettingData.SaveFile();
|
||||||
|
|
||||||
|
result = new CollectorContext
|
||||||
|
{
|
||||||
|
Package = package,
|
||||||
|
Group = group,
|
||||||
|
Collector = collector,
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将收集器移动到目标包裹的第一个分组
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collector">要移动的收集器实例</param>
|
||||||
|
/// <param name="fromGroup">原分组</param>
|
||||||
|
/// <param name="toPackage">目标包裹</param>
|
||||||
|
/// <returns>目标包裹无分组或无需移动时返回 false</returns>
|
||||||
|
private static bool MoveCollectorToPackage(BundleCollector collector, BundleCollectorGroup fromGroup, BundleCollectorPackage toPackage)
|
||||||
|
{
|
||||||
|
if (toPackage.Groups.Count == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Package '{toPackage.PackageName}' has no group. Please create a group first.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var toGroup = toPackage.Groups[0];
|
||||||
|
if (toGroup == fromGroup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RecordUndo("YooAsset.Inspector Move Collector Package");
|
||||||
|
fromGroup.Collectors.Remove(collector);
|
||||||
|
toGroup.Collectors.Add(collector);
|
||||||
|
BundleCollectorSettingData.ModifyCollector(toGroup, collector);
|
||||||
|
BundleCollectorSettingData.SaveFile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将收集器在同一包裹内移动到目标分组
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collector">要移动的收集器实例</param>
|
||||||
|
/// <param name="fromGroup">原分组</param>
|
||||||
|
/// <param name="toGroup">目标分组</param>
|
||||||
|
private static void MoveCollectorToGroup(BundleCollector collector, BundleCollectorGroup fromGroup, BundleCollectorGroup toGroup)
|
||||||
|
{
|
||||||
|
if (toGroup == fromGroup)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RecordUndo("YooAsset.Inspector Move Collector Group");
|
||||||
|
fromGroup.Collectors.Remove(collector);
|
||||||
|
toGroup.Collectors.Add(collector);
|
||||||
|
BundleCollectorSettingData.ModifyCollector(toGroup, collector);
|
||||||
|
BundleCollectorSettingData.SaveFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标记收集器已修改并持久化配置文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="group">收集器所属分组</param>
|
||||||
|
/// <param name="collector">被修改的收集器</param>
|
||||||
|
private static void CommitModify(BundleCollectorGroup group, BundleCollector collector)
|
||||||
|
{
|
||||||
|
BundleCollectorSettingData.ModifyCollector(group, collector);
|
||||||
|
BundleCollectorSettingData.SaveFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在修改配置前登记 Undo,使操作可撤销。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Undo 操作名称</param>
|
||||||
|
private static void RecordUndo(string name)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(BundleCollectorSettingData.Setting, name);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9f06fac18179b404988b68a675c421af
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -3,19 +3,19 @@ using UnityEngine;
|
|||||||
using YooAsset;
|
using YooAsset;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 游戏对象弱引用,序列化时只保存资源 GUID
|
/// 资源弱引用基类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class GameObjectReference
|
public abstract class AssetReference
|
||||||
{
|
{
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private string _packageName = "DefaultPackage";
|
protected string _packageName = "DefaultPackage";
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private string _assetGUID = "";
|
protected string _assetGUID = "";
|
||||||
|
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
private AssetHandle _handle;
|
protected AssetHandle _handle;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 资源所属的包裹名称
|
/// 资源所属的包裹名称
|
||||||
@@ -27,6 +27,16 @@ public class GameObjectReference
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string AssetGUID => _assetGUID;
|
public string AssetGUID => _assetGUID;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前加载句柄(未加载时为 null)
|
||||||
|
/// </summary>
|
||||||
|
public AssetHandle Handle => _handle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 该引用负责加载的资源类型,由子类指定
|
||||||
|
/// </summary>
|
||||||
|
public abstract Type AssetType { get; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查运行时引用键是否有效
|
/// 检查运行时引用键是否有效
|
||||||
@@ -37,18 +47,18 @@ public class GameObjectReference
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var package = YooAssets.GetPackage(_packageName);
|
var package = YooAssets.GetPackage(_packageName);
|
||||||
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, typeof(GameObject));
|
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, AssetType);
|
||||||
return assetInfo.IsValid;
|
return assetInfo.IsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步加载引用的游戏对象
|
/// 异步加载引用的资源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>加载操作句柄</returns>
|
/// <returns>加载操作句柄</returns>
|
||||||
public AssetHandle LoadAssetAsync()
|
public AssetHandle LoadAssetAsync()
|
||||||
{
|
{
|
||||||
if (_handle != null)
|
if (_handle != null)
|
||||||
throw new InvalidOperationException("GameObject reference has already been loaded. Release it first.");
|
throw new InvalidOperationException($"{GetType().Name} has already been loaded. Release it first.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_packageName))
|
if (string.IsNullOrEmpty(_packageName))
|
||||||
throw new ArgumentException("Package name is not set.", nameof(_packageName));
|
throw new ArgumentException("Package name is not set.", nameof(_packageName));
|
||||||
@@ -56,7 +66,7 @@ public class GameObjectReference
|
|||||||
throw new ArgumentException("Asset GUID is not set.", nameof(_assetGUID));
|
throw new ArgumentException("Asset GUID is not set.", nameof(_assetGUID));
|
||||||
|
|
||||||
var package = YooAssets.GetPackage(_packageName);
|
var package = YooAssets.GetPackage(_packageName);
|
||||||
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, typeof(GameObject));
|
var assetInfo = package.GetAssetInfoByGuid(_assetGUID, AssetType);
|
||||||
_handle = package.LoadAssetAsync(assetInfo);
|
_handle = package.LoadAssetAsync(assetInfo);
|
||||||
return _handle;
|
return _handle;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7de4fe4f4d6834c47977a97c7ad20bd3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GameObject 资源弱引用
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class AssetReferenceGameObject : AssetReference
|
||||||
|
{
|
||||||
|
public override Type AssetType => typeof(GameObject);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 764d480d7edd8cd48b8105dc6b24bd2a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -3,36 +3,58 @@ using UnityEngine;
|
|||||||
using YooAsset;
|
using YooAsset;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 演示如何使用 GameObjectReference 弱引用加载并实例化游戏对象
|
/// 演示如何使用 AssetReference 弱引用加载不同类型的资源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AssetReferenceSample : MonoBehaviour
|
public class AssetReferenceSample : MonoBehaviour
|
||||||
{
|
{
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private GameObjectReference _reference;
|
private AssetReferenceGameObject _prefabReference;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private AssetReferenceTexture2D _textureReference;
|
||||||
|
|
||||||
private IEnumerator Start()
|
private IEnumerator Start()
|
||||||
{
|
{
|
||||||
if (_reference.RuntimeKeyIsValid() == false)
|
// 加载并实例化预制体
|
||||||
|
if (_prefabReference.RuntimeKeyIsValid())
|
||||||
{
|
{
|
||||||
yield break;
|
AssetHandle handle = _prefabReference.LoadAssetAsync();
|
||||||
}
|
|
||||||
|
|
||||||
AssetHandle handle = _reference.LoadAssetAsync();
|
|
||||||
yield return handle;
|
yield return handle;
|
||||||
|
|
||||||
if (handle.Status == EOperationStatus.Succeeded)
|
if (handle.Status == EOperationStatus.Succeeded)
|
||||||
{
|
{
|
||||||
GameObject instance = handle.InstantiateSync(new InstantiateOptions(true, transform, false));
|
GameObject instance = handle.InstantiateSync(new InstantiateOptions(true, transform, false));
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
Debug.LogError($"Failed to instantiate GameObject reference '{_reference.AssetGUID}'.");
|
Debug.LogError($"Failed to instantiate GameObject reference '{_prefabReference.AssetGUID}'.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError($"Failed to load GameObject reference '{_reference.AssetGUID}': {handle.Error}.");
|
Debug.LogError($"Failed to load GameObject reference '{_prefabReference.AssetGUID}': {handle.Error}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载纹理并赋值给渲染器材质
|
||||||
|
if (_textureReference.RuntimeKeyIsValid())
|
||||||
|
{
|
||||||
|
AssetHandle handle = _textureReference.LoadAssetAsync();
|
||||||
|
yield return handle;
|
||||||
|
|
||||||
|
if (handle.Status == EOperationStatus.Succeeded)
|
||||||
|
{
|
||||||
|
var renderer = GetComponent<Renderer>();
|
||||||
|
if (renderer != null)
|
||||||
|
renderer.material.mainTexture = handle.AssetObject as Texture2D;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"Failed to load Texture2D reference '{_textureReference.AssetGUID}': {handle.Error}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
_reference.ReleaseAsset();
|
_prefabReference?.ReleaseAsset();
|
||||||
|
_textureReference?.ReleaseAsset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture2D 资源弱引用
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class AssetReferenceTexture2D : AssetReference
|
||||||
|
{
|
||||||
|
public override Type AssetType => typeof(Texture2D);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0c6c6d8423826d24083eb0608e0fd023
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture3D 资源弱引用
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class AssetReferenceTexture3D : AssetReference
|
||||||
|
{
|
||||||
|
public override Type AssetType => typeof(Texture3D);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: be5c51911e8f45a45b7ed11af7d0b50c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -11,14 +11,14 @@ public static class AlipayFileSystemCreater
|
|||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# 支付宝小游戏文件系统
|
||||||
|
|
||||||
|
该示例用于在 YooAsset 的 WebGL 运行模式下接入支付宝小游戏。
|
||||||
|
|
||||||
|
参考文档:[支付宝小游戏开发文档](https://opendocs.alipay.com/mini-game/)
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
先安装支付宝小游戏 Unity/团结 WebGL 适配 SDK,并将项目切换到 WebGL 构建目标。
|
||||||
|
|
||||||
|
在 WebGL Player 的 Scripting Define Symbols 中启用以下宏:
|
||||||
|
|
||||||
|
- `UNITY_ALIMINIGAME`
|
||||||
|
|
||||||
|
该宏是 YooAsset 支付宝小游戏示例约定的编译开关,用于和其它小游戏平台适配代码保持一致。
|
||||||
|
|
||||||
|
如果启用宏后编译提示找不到 `AlipaySdk`、`APAssetBundle` 或 `DownloadHandlerAPAssetBundle`,请确认支付宝 SDK 已导入,并将支付宝 SDK 的程序集引用添加到 `YooAsset.MiniGame.asmdef`。
|
||||||
|
|
||||||
|
## 初始化 YooAsset
|
||||||
|
|
||||||
|
在支付宝小游戏构建中初始化 `WebPlayModeOptions` 时,使用 `AlipayFileSystemCreater` 创建文件系统参数。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME && !UNITY_EDITOR
|
||||||
|
var createParameters = new WebPlayModeOptions();
|
||||||
|
|
||||||
|
string defaultHostServer = GetHostServerURL();
|
||||||
|
string fallbackHostServer = GetHostServerURL();
|
||||||
|
IRemoteService remoteService = new RemoteService(defaultHostServer, fallbackHostServer);
|
||||||
|
|
||||||
|
createParameters.WebServerFileSystemParameters =
|
||||||
|
AlipayFileSystemCreater.CreateFileSystemParameters(remoteService);
|
||||||
|
|
||||||
|
var initializationOperation = package.InitializePackageAsync(createParameters);
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
支付宝小游戏底层会对远程 AssetBundle 请求做平台适配,业务侧仍然按照远程异步加载流程使用 YooAsset。
|
||||||
|
|
||||||
|
## 资源包命名
|
||||||
|
|
||||||
|
支付宝小游戏构建推荐让资源包文件名携带 hash。YooAsset 推荐只使用 `HashName` 文件命名风格。
|
||||||
|
|
||||||
|
`HashName` 会生成纯 hash 文件名,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
8d265a9dfd6cb7669cdb8b726f0afb1e.bundle
|
||||||
|
```
|
||||||
|
|
||||||
|
该命名方式更适合小游戏平台的缓存和更新识别,也能避免暴露原始 Bundle 名称。支付宝小游戏构建不建议使用 `BundleName` 或 `BundleName_HashName`。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
加密 AssetBundle 仍然会走 YooAsset 常规的 Web 下载和解密流程。非加密 AssetBundle 会使用支付宝平台适配器,并通过 `APAssetBundle.GetAssetBundle` 发起请求。
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7fcf69ed8b0d43141bdf2412c9822ddc
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -11,14 +11,14 @@ public static class KuaiShouFileSystemCreater
|
|||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ public static class OppoFileSystemCreater
|
|||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# TapTap 小游戏文件系统
|
||||||
|
|
||||||
|
该示例用于在 YooAsset 的 WebGL 运行模式下接入 TapTap 小游戏。
|
||||||
|
|
||||||
|
参考文档:[TapTap 小游戏 Unity 适配指南](https://developer.taptap.cn/minigameapidoc/dev/engine/unity-adaptation/guide/)
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
先安装 TapTap 小游戏 Unity/团结 WebGL 适配 SDK,并将项目切换到 WebGL 构建目标。
|
||||||
|
|
||||||
|
在 WebGL Player 的 Scripting Define Symbols 中启用以下宏:
|
||||||
|
|
||||||
|
- `TAPMINIGAME`
|
||||||
|
|
||||||
|
该宏是 YooAsset TapTap 小游戏示例约定的编译开关,用于和其它小游戏平台适配代码保持一致。
|
||||||
|
|
||||||
|
如果启用宏后编译提示找不到 `TapTapMiniGame`、`TapAssetBundle` 或 `DownloadHandlerTapAssetBundle`,请确认 TapTap SDK 已导入,并将 TapTap SDK 的程序集引用添加到 `YooAsset.MiniGame.asmdef`。
|
||||||
|
|
||||||
|
## 初始化 YooAsset
|
||||||
|
|
||||||
|
在 TapTap 小游戏构建中初始化 `WebPlayModeOptions` 时,使用 `TaptapFileSystemCreater` 创建文件系统参数。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
#if UNITY_WEBGL && TAPMINIGAME && !UNITY_EDITOR
|
||||||
|
var createParameters = new WebPlayModeOptions();
|
||||||
|
|
||||||
|
string defaultHostServer = GetHostServerURL();
|
||||||
|
string fallbackHostServer = GetHostServerURL();
|
||||||
|
IRemoteService remoteService = new RemoteService(defaultHostServer, fallbackHostServer);
|
||||||
|
|
||||||
|
createParameters.WebServerFileSystemParameters =
|
||||||
|
TaptapFileSystemCreater.CreateFileSystemParameters(remoteService);
|
||||||
|
|
||||||
|
var initializationOperation = package.InitializePackageAsync(createParameters);
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
TapTap 小游戏底层会对远程 AssetBundle 请求做平台适配,业务侧仍然按照远程异步加载流程使用 YooAsset。
|
||||||
|
|
||||||
|
## 资源包命名
|
||||||
|
|
||||||
|
TapTap 小游戏构建推荐让资源包文件名携带 hash。YooAsset 推荐只使用 `HashName` 文件命名风格。
|
||||||
|
|
||||||
|
`HashName` 会生成纯 hash 文件名,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
8d265a9dfd6cb7669cdb8b726f0afb1e.bundle
|
||||||
|
```
|
||||||
|
|
||||||
|
该命名方式更适合小游戏平台的缓存和更新识别,也能避免暴露原始 Bundle 名称。TapTap 小游戏构建不建议使用 `BundleName` 或 `BundleName_HashName`。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
加密 AssetBundle 仍然会走 YooAsset 常规的 Web 下载和解密流程。非加密 AssetBundle 会使用 TapTap 平台适配器,并通过 `TapAssetBundle.GetAssetBundle` 发起请求。
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 52a8b3cdfd92faf4d8ed04f35b602210
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -12,14 +12,14 @@ public static class TaptapFileSystemCreater
|
|||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ public static class TiktokFileSystemCreater
|
|||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ public static class VivoFileSystemCreater
|
|||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
public static FileSystemParameters CreateFileSystemParameters(IRemoteService remoteService, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor)
|
||||||
{
|
{
|
||||||
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
var fileSystemParams = CreateBaseFileSystemParameters(remoteService);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public static class WechatFileSystemCreater
|
|||||||
fileSystemParams.AddParameter(EFileSystemParameter.WebPlatformStrategy, new WechatPlatform());
|
fileSystemParams.AddParameter(EFileSystemParameter.WebPlatformStrategy, new WechatPlatform());
|
||||||
|
|
||||||
if (assetBundleDecryptor != null)
|
if (assetBundleDecryptor != null)
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.AssetbundleDecryptor, assetBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.AssetBundleDecryptor, assetBundleDecryptor);
|
||||||
if (rawBundleDecryptor != null)
|
if (rawBundleDecryptor != null)
|
||||||
fileSystemParams.AddParameter(EFileSystemParameter.RawbundleDecryptor, rawBundleDecryptor);
|
fileSystemParams.AddParameter(EFileSystemParameter.RawBundleDecryptor, rawBundleDecryptor);
|
||||||
return fileSystemParams;
|
return fileSystemParams;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
#if YOOASSET_UNITASK_SUPPORT
|
#if YOOASSET_UNITASK_SUPPORT
|
||||||
#if UNITY_2020_1_OR_NEWER && ! UNITY_2021
|
|
||||||
#define UNITY_2020_BUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using YooAsset;
|
using YooAsset;
|
||||||
@@ -40,7 +36,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
TaskPool.RegisterSizeGetter(typeof(HandleBaseConfiguredSource), () => pool.Size);
|
TaskPool.RegisterSizeGetter(typeof(HandleBaseConfiguredSource), () => pool.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly Action<HandleBase> completedCallback;
|
|
||||||
HandleBase handle;
|
HandleBase handle;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
@@ -52,7 +47,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
HandleBaseConfiguredSource()
|
HandleBaseConfiguredSource()
|
||||||
{
|
{
|
||||||
completedCallback = HandleCompleted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource Create(HandleBase handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
public static IUniTaskSource Create(HandleBase handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||||
@@ -85,11 +79,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
TaskTracker.TrackActiveTask(result, 3);
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
// BUG 在 Unity 2020.3.36 版本测试中, IL2Cpp 会报 如下错误
|
// 注意:统一用强类型回调订阅 Handle.Completed,修复 IL2CPP 逆变委托崩溃
|
||||||
// BUG ArgumentException: Incompatible Delegate Types. First is System.Action`1[[YooAsset.AssetHandle, YooAsset, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] second is System.Action`1[[YooAsset.HandleBase, YooAsset, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]
|
|
||||||
// BUG 也可能报的是 Action '1' Action '1' 的 InvalidCastException
|
|
||||||
// BUG 此处不得不这么修改, 如果后续 Unity 修复了这个问题, 可以恢复之前的写法
|
|
||||||
#if UNITY_2020_BUG
|
|
||||||
switch (handle)
|
switch (handle)
|
||||||
{
|
{
|
||||||
case AssetHandle asset_handle:
|
case AssetHandle asset_handle:
|
||||||
@@ -108,38 +98,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
all_assets_handle.Completed += result.AllAssetsContinuation;
|
all_assets_handle.Completed += result.AllAssetsContinuation;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
switch (handle)
|
|
||||||
{
|
|
||||||
case AssetHandle asset_handle:
|
|
||||||
asset_handle.Completed += result.completedCallback;
|
|
||||||
break;
|
|
||||||
case SceneHandle scene_handle:
|
|
||||||
scene_handle.Completed += result.completedCallback;
|
|
||||||
break;
|
|
||||||
case SubAssetsHandle sub_asset_handle:
|
|
||||||
sub_asset_handle.Completed += result.completedCallback;
|
|
||||||
break;
|
|
||||||
case BundleFileHandle bundle_file_handle:
|
|
||||||
bundle_file_handle.Completed += result.completedCallback;
|
|
||||||
break;
|
|
||||||
case AllAssetsHandle all_assets_handle:
|
|
||||||
all_assets_handle.Completed += result.completedCallback;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
token = result.core.Version;
|
token = result.core.Version;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_2020_BUG
|
|
||||||
void AssetContinuation(AssetHandle _) => HandleCompleted(null);
|
void AssetContinuation(AssetHandle _) => HandleCompleted(null);
|
||||||
void SceneContinuation(SceneHandle _) => HandleCompleted(null);
|
void SceneContinuation(SceneHandle _) => HandleCompleted(null);
|
||||||
void SubContinuation(SubAssetsHandle _) => HandleCompleted(null);
|
void SubContinuation(SubAssetsHandle _) => HandleCompleted(null);
|
||||||
void BundleFileContinuation(BundleFileHandle _) => HandleCompleted(null);
|
void BundleFileContinuation(BundleFileHandle _) => HandleCompleted(null);
|
||||||
void AllAssetsContinuation(AllAssetsHandle _) => HandleCompleted(null);
|
void AllAssetsContinuation(AllAssetsHandle _) => HandleCompleted(null);
|
||||||
#endif
|
|
||||||
|
|
||||||
void HandleCompleted(HandleBase _)
|
void HandleCompleted(HandleBase _)
|
||||||
{
|
{
|
||||||
@@ -162,7 +130,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (handle == null || !handle.IsValid) return;
|
if (handle == null || !handle.IsValid) return;
|
||||||
|
|
||||||
#if UNITY_2020_BUG
|
|
||||||
switch (handle)
|
switch (handle)
|
||||||
{
|
{
|
||||||
case AssetHandle asset_handle:
|
case AssetHandle asset_handle:
|
||||||
@@ -181,26 +148,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
all_assets_handle.Completed -= AllAssetsContinuation;
|
all_assets_handle.Completed -= AllAssetsContinuation;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
switch (handle)
|
|
||||||
{
|
|
||||||
case AssetHandle asset_handle:
|
|
||||||
asset_handle.Completed -= completedCallback;
|
|
||||||
break;
|
|
||||||
case SceneHandle scene_handle:
|
|
||||||
scene_handle.Completed -= completedCallback;
|
|
||||||
break;
|
|
||||||
case SubAssetsHandle sub_asset_handle:
|
|
||||||
sub_asset_handle.Completed -= completedCallback;
|
|
||||||
break;
|
|
||||||
case BundleFileHandle bundle_file_handle:
|
|
||||||
bundle_file_handle.Completed -= completedCallback;
|
|
||||||
break;
|
|
||||||
case AllAssetsHandle all_assets_handle:
|
|
||||||
all_assets_handle.Completed -= completedCallback;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetResult(short token)
|
public void GetResult(short token)
|
||||||
|
|||||||
Reference in New Issue
Block a user