Compare commits

..

27 Commits

Author SHA1 Message Date
何冠峰
53163a75ae Update CHANGELOG.md 2025-07-01 16:46:10 +08:00
何冠峰
273401cb20 Update package.json 2025-07-01 16:45:50 +08:00
何冠峰
97fe3b0681 update file system
修正2.3.11版本同步加载本地加密文件失败的问题。
2025-07-01 16:40:01 +08:00
何冠峰
d401086fd1 update test sample 2025-07-01 15:32:44 +08:00
何冠峰
e3a12ef361 style : file system code style 2025-07-01 11:06:41 +08:00
何冠峰
1b0288fcd0 update mini game
微信小游戏和抖音小游戏支持资源清单加密。
2025-06-30 16:19:59 +08:00
何冠峰
3ee94fb3b9 update extension sample 2025-06-30 15:43:47 +08:00
何冠峰
a0ea80c158 Update CHANGELOG.md 2025-06-30 12:06:30 +08:00
何冠峰
264415b362 Update package.json 2025-06-30 12:06:07 +08:00
何冠峰
6a76d44c38 update test sample 2025-06-30 11:30:56 +08:00
何冠峰
cebfd57851 update test sample 2025-06-30 11:22:38 +08:00
何冠峰
60eb1c3522 update test sample
修正单元测试失败
2025-06-30 11:07:46 +08:00
何冠峰
40c82835bf style : code style 2025-06-30 10:53:16 +08:00
何冠峰
a13913f572 Merge pull request #582 from hhmmLife/dev
fix: 只有递归收集依赖时,依赖列表中才默认包含主资源
2025-06-30 10:47:28 +08:00
何冠峰
150b46a0a7 update file system
新增ICopyLocalFileServices服务类
2025-06-27 17:42:57 +08:00
何冠峰
ebde5a52d3 fix #585 2025-06-25 19:27:52 +08:00
何冠峰
e57466e9e2 style : file system code 2025-06-25 18:12:37 +08:00
何冠峰
6f7fca7b34 perf : main thread sleep one 2025-06-25 18:10:50 +08:00
何冠峰
756331fe0b style : file system code 2025-06-25 18:04:53 +08:00
何冠峰
5139e2f3a7 update extension sample 2025-06-23 18:57:48 +08:00
hhmmLife
1c4aba6db5 fix: 只有递归收集依赖时,依赖列表中才默认包含主资源 2025-06-23 00:56:50 +08:00
何冠峰
44faa0c5e6 fix #572
修复了资源收集页面指定收集的预制体名称变动的问题。
2025-06-20 17:55:51 +08:00
何冠峰
72c97341b1 fix #579 2025-06-20 14:03:12 +08:00
何冠峰
9acc240b5a update extension sample 2025-06-20 11:36:56 +08:00
何冠峰
ed89e73d26 fix #576
资源清单加密和解密
2025-06-20 11:36:29 +08:00
何冠峰
9e33df0375 style :services code 2025-06-20 11:29:22 +08:00
何冠峰
6c98f9a09d update resource manager
新增初始化参数:WebGLForceSyncLoadAsset
2025-06-18 11:12:42 +08:00
91 changed files with 1308 additions and 213 deletions

View File

@@ -2,6 +2,65 @@
All notable changes to this package will be documented in this file.
## [2.3.12] - 2025-07-01
### Improvements
- 优化了同步接口导致的资源拷贝和资源验证性能开销高的现象。
- 微信小游戏和抖音小游戏支持资源清单加密。
### Fixed
- (#579) 修复了2.3.10版本资源包构建页面里CopyBuildinFileParam无法编辑问题。
- (#572) 修复了资源收集页面指定收集的预制体名称变动的问题。
- (#582) 修复了非递归收集依赖时,依赖列表中才包含主资源的问题。
### Added
- 新增初始化参数WebGLForceSyncLoadAsset
```csharp
public abstract class InitializeParameters
{
/// <summary>
/// WebGL平台强制同步加载资源对象
/// </summary>Add commentMore actions
public bool WebGLForceSyncLoadAsset = false;
}
```
- (#576) 新增了资源清单服务类IManifestServices
```csharp
/// <summary>
/// 资源清单文件处理服务接口
/// </summary>
public interface IManifestServices
{
/// <summary>
/// 处理资源清单(压缩和加密)
/// </summary>
byte[] ProcessManifest(byte[] fileData);
/// <summary>
/// 还原资源清单(解压和解密)
/// </summary>
byte[] RestoreManifest(byte[] fileData);
}
```
- (#585) 新增了本地文件拷贝服务类ICopyLocalFileServices
```csharp
/// <summary>
/// 本地文件拷贝服务类
/// </summary>
public interface ICopyLocalFileServices
{
void CopyFile(LocalFileInfo sourceFileInfo, string destFilePath);
}
```
## [2.3.10] - 2025-06-17
### Improvements

View File

@@ -67,15 +67,27 @@ namespace YooAsset.Editor
EditorPrefs.SetString(key, buildinFileCopyParams);
}
// EncyptionClassName
public static string GetPackageEncyptionClassName(string packageName, string buildPipeline)
// EncyptionServicesClassName
public static string GetPackageEncyptionServicesClassName(string packageName, string buildPipeline)
{
string key = $"{Application.productName}_{packageName}_{buildPipeline}_EncyptionClassName";
return EditorPrefs.GetString(key, string.Empty);
string key = $"{Application.productName}_{packageName}_{buildPipeline}_EncyptionServicesClassName";
return EditorPrefs.GetString(key, $"{typeof(EncryptionNone).FullName}");
}
public static void SetPackageEncyptionClassName(string packageName, string buildPipeline, string encyptionClassName)
public static void SetPackageEncyptionServicesClassName(string packageName, string buildPipeline, string encyptionClassName)
{
string key = $"{Application.productName}_{packageName}_{buildPipeline}_EncyptionClassName";
string key = $"{Application.productName}_{packageName}_{buildPipeline}_EncyptionServicesClassName";
EditorPrefs.SetString(key, encyptionClassName);
}
// ManifestServicesClassName
public static string GetPackageManifestServicesClassName(string packageName, string buildPipeline)
{
string key = $"{Application.productName}_{packageName}_{buildPipeline}_ManifestServicesClassName";
return EditorPrefs.GetString(key, $"{typeof(ManifestNone).FullName}");
}
public static void SetPackageManifestServicesClassName(string packageName, string buildPipeline, string encyptionClassName)
{
string key = $"{Application.productName}_{packageName}_{buildPipeline}_ManifestServicesClassName";
EditorPrefs.SetString(key, encyptionClassName);
}

View File

@@ -98,6 +98,11 @@ namespace YooAsset.Editor
/// </summary>
public IEncryptionServices EncryptionServices;
/// <summary>
/// 资源清单服务类
/// </summary>
public IManifestServices ManifestServices;
private string _pipelineOutputDirectory = string.Empty;
private string _packageOutputDirectory = string.Empty;

View File

@@ -14,7 +14,8 @@ namespace YooAsset.Editor
{
string buildinRootDirectory = buildParametersContext.GetBuildinRootDirectory();
string buildPackageName = buildParametersContext.Parameters.PackageName;
DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(buildPackageName, buildinRootDirectory);
var manifestServices = buildParametersContext.Parameters.ManifestServices;
DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(manifestServices, buildPackageName, buildinRootDirectory);
// 刷新目录
AssetDatabase.Refresh();

View File

@@ -58,7 +58,7 @@ namespace YooAsset.Editor
if (processBundleDepends)
ProcessBuiltinBundleDependency(context, manifest);
// 创建补丁清单文本文件
// 创建资源清单文本文件
{
string fileName = YooAssetSettingsData.GetManifestJsonFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}";
@@ -66,18 +66,18 @@ namespace YooAsset.Editor
BuildLogger.Log($"Create package manifest file: {filePath}");
}
// 创建补丁清单二进制文件
// 创建资源清单二进制文件
string packageHash;
string packagePath;
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(buildParameters.PackageName, buildParameters.PackageVersion);
packagePath = $"{packageOutputDirectory}/{fileName}";
ManifestTools.SerializeToBinary(packagePath, manifest);
ManifestTools.SerializeToBinary(packagePath, manifest, buildParameters.ManifestServices);
packageHash = HashUtility.FileCRC32(packagePath);
BuildLogger.Log($"Create package manifest file: {packagePath}");
}
// 创建补丁清单哈希文件
// 创建资源清单哈希文件
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}";
@@ -85,7 +85,7 @@ namespace YooAsset.Editor
BuildLogger.Log($"Create package manifest hash file: {filePath}");
}
// 创建补丁清单版本文件
// 创建资源清单版本文件
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(buildParameters.PackageName);
string filePath = $"{packageOutputDirectory}/{fileName}";
@@ -97,7 +97,7 @@ namespace YooAsset.Editor
{
ManifestContext manifestContext = new ManifestContext();
byte[] bytesData = FileUtility.ReadAllBytes(packagePath);
manifestContext.Manifest = ManifestTools.DeserializeFromBinary(bytesData);
manifestContext.Manifest = ManifestTools.DeserializeFromBinary(bytesData, buildParameters.ManifestServices);
context.SetContextObject(manifestContext);
}
}

View File

@@ -43,7 +43,8 @@ namespace YooAsset.Editor
buildReport.Summary.EnableSharePackRule = buildParameters.EnableSharePackRule;
buildReport.Summary.SingleReferencedPackAlone = buildParameters.SingleReferencedPackAlone;
buildReport.Summary.FileNameStyle = buildParameters.FileNameStyle;
buildReport.Summary.EncryptionClassName = buildParameters.EncryptionServices == null ? "null" : buildParameters.EncryptionServices.GetType().FullName;
buildReport.Summary.EncryptionServicesClassName = buildParameters.EncryptionServices == null ? "null" : buildParameters.EncryptionServices.GetType().FullName;
buildReport.Summary.ManifestServicesClassName = buildParameters.ManifestServices == null ? "null" : buildParameters.ManifestServices.GetType().FullName;
if (buildParameters is BuiltinBuildParameters)
{
var builtinBuildParameters = buildParameters as BuiltinBuildParameters;

View File

@@ -0,0 +1,15 @@

namespace YooAsset.Editor
{
public class ManifestNone : IManifestServices
{
public byte[] ProcessManifest(byte[] fileData)
{
return fileData;
}
public byte[] RestoreManifest(byte[] fileData)
{
return fileData;
}
}
}

View File

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

View File

@@ -44,19 +44,33 @@ namespace YooAsset.Editor
}
/// <summary>
/// 创建加密类实例
/// 创建资源加密服务类实例
/// </summary>
protected IEncryptionServices CreateEncryptionInstance()
protected IEncryptionServices CreateEncryptionServicesInstance()
{
var encyptionClassName = AssetBundleBuilderSetting.GetPackageEncyptionClassName(PackageName, PipelineName);
var encryptionClassTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
var classType = encryptionClassTypes.Find(x => x.FullName.Equals(encyptionClassName));
var className = AssetBundleBuilderSetting.GetPackageEncyptionServicesClassName(PackageName, PipelineName);
var classTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
var classType = classTypes.Find(x => x.FullName.Equals(className));
if (classType != null)
return (IEncryptionServices)Activator.CreateInstance(classType);
else
return null;
}
/// <summary>
/// 创建资源清单服务类实例
/// </summary>
protected IManifestServices CreateManifestServicesInstance()
{
var className = AssetBundleBuilderSetting.GetPackageManifestServicesClassName(PackageName, PipelineName);
var classTypes = EditorTools.GetAssignableTypes(typeof(IManifestServices));
var classType = classTypes.Find(x => x.FullName.Equals(className));
if (classType != null)
return (IManifestServices)Activator.CreateInstance(classType);
else
return null;
}
#region UI元素通用处理方法
protected void SetBuildOutputField(TextField textField)
{
@@ -111,11 +125,15 @@ namespace YooAsset.Editor
AssetBundleBuilderSetting.SetPackageBuildinFileCopyOption(PackageName, PipelineName, (EBuildinFileCopyOption)enumField.value);
// 设置内置资源标签显隐
bool tagsFiledVisible = buildinFileCopyOption == EBuildinFileCopyOption.ClearAndCopyByTags || buildinFileCopyOption == EBuildinFileCopyOption.OnlyCopyByTags;
tagField.visible = tagsFiledVisible;
SetCopyBuildinFileTagsVisible(tagField);
});
UIElementsTools.SetElementLabelMinWidth(enumField, LabelMinWidth);
}
protected void SetCopyBuildinFileTagsVisible(TextField tagField)
{
var option = AssetBundleBuilderSetting.GetPackageBuildinFileCopyOption(PackageName, PipelineName);
tagField.visible = option == EBuildinFileCopyOption.ClearAndCopyByTags || option == EBuildinFileCopyOption.OnlyCopyByTags;
}
protected void SetCopyBuildinFileTagsField(TextField textField)
{
// 首包文件拷贝参数
@@ -149,35 +167,66 @@ namespace YooAsset.Editor
});
UIElementsTools.SetElementLabelMinWidth(toggle, LabelMinWidth);
}
protected PopupField<Type> CreateEncryptionField(VisualElement container)
protected PopupField<Type> CreateEncryptionServicesField(VisualElement container)
{
// 加密方法
var encryptionClassTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
if (encryptionClassTypes.Count > 0)
// 加密服务类
var classTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices));
if (classTypes.Count > 0)
{
var encyptionClassName = AssetBundleBuilderSetting.GetPackageEncyptionClassName(PackageName, PipelineName);
int defaultIndex = encryptionClassTypes.FindIndex(x => x.FullName.Equals(encyptionClassName));
var className = AssetBundleBuilderSetting.GetPackageEncyptionServicesClassName(PackageName, PipelineName);
int defaultIndex = classTypes.FindIndex(x => x.FullName.Equals(className));
if (defaultIndex < 0)
defaultIndex = 0;
var encryptionField = new PopupField<Type>(encryptionClassTypes, defaultIndex);
encryptionField.label = "Encryption";
encryptionField.style.width = StyleWidth;
encryptionField.RegisterValueChangedCallback(evt =>
var popupField = new PopupField<Type>(classTypes, defaultIndex);
popupField.label = "Encryption Services";
popupField.style.width = StyleWidth;
popupField.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSetting.SetPackageEncyptionClassName(PackageName, PipelineName, encryptionField.value.FullName);
AssetBundleBuilderSetting.SetPackageEncyptionServicesClassName(PackageName, PipelineName, popupField.value.FullName);
});
container.Add(encryptionField);
UIElementsTools.SetElementLabelMinWidth(encryptionField, LabelMinWidth);
return encryptionField;
container.Add(popupField);
UIElementsTools.SetElementLabelMinWidth(popupField, LabelMinWidth);
return popupField;
}
else
{
var encryptionField = new PopupField<Type>();
encryptionField.label = "Encryption";
encryptionField.style.width = StyleWidth;
container.Add(encryptionField);
UIElementsTools.SetElementLabelMinWidth(encryptionField, LabelMinWidth);
return encryptionField;
var popupField = new PopupField<Type>();
popupField.label = "Encryption Services";
popupField.style.width = StyleWidth;
container.Add(popupField);
UIElementsTools.SetElementLabelMinWidth(popupField, LabelMinWidth);
return popupField;
}
}
protected PopupField<Type> CreateManifestServicesField(VisualElement container)
{
// 清单服务类
var classTypes = EditorTools.GetAssignableTypes(typeof(IManifestServices));
if (classTypes.Count > 0)
{
var className = AssetBundleBuilderSetting.GetPackageManifestServicesClassName(PackageName, PipelineName);
int defaultIndex = classTypes.FindIndex(x => x.FullName.Equals(className));
if (defaultIndex < 0)
defaultIndex = 0;
var popupField = new PopupField<Type>(classTypes, defaultIndex);
popupField.label = "Manifest Services";
popupField.style.width = StyleWidth;
popupField.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSetting.SetPackageManifestServicesClassName(PackageName, PipelineName, popupField.value.FullName);
});
container.Add(popupField);
UIElementsTools.SetElementLabelMinWidth(popupField, LabelMinWidth);
return popupField;
}
else
{
var popupField = new PopupField<Type>();
popupField.label = "Manifest Services";
popupField.style.width = StyleWidth;
container.Add(popupField);
UIElementsTools.SetElementLabelMinWidth(popupField, LabelMinWidth);
return popupField;
}
}
#endregion

View File

@@ -16,7 +16,8 @@ namespace YooAsset.Editor
protected TemplateContainer Root;
protected TextField _buildOutputField;
protected TextField _buildVersionField;
protected PopupField<Type> _encryptionField;
protected PopupField<Type> _encryptionServicesField;
protected PopupField<Type> _manifestServicesField;
protected EnumField _compressionField;
protected EnumField _outputNameStyleField;
protected EnumField _copyBuildinFileOptionField;
@@ -43,9 +44,10 @@ namespace YooAsset.Editor
_buildVersionField = Root.Q<TextField>("BuildVersion");
SetBuildVersionField(_buildVersionField);
// 加密方法
var encryptionContainer = Root.Q("EncryptionContainer");
_encryptionField = CreateEncryptionField(encryptionContainer);
// 服务类
var popupContainer = Root.Q("PopupContainer");
_encryptionServicesField = CreateEncryptionServicesField(popupContainer);
_manifestServicesField = CreateManifestServicesField(popupContainer);
// 压缩方式选项
_compressionField = Root.Q<EnumField>("Compression");
@@ -58,6 +60,7 @@ namespace YooAsset.Editor
// 首包文件拷贝参数
_copyBuildinFileTagsField = Root.Q<TextField>("CopyBuildinFileParam");
SetCopyBuildinFileTagsField(_copyBuildinFileTagsField);
SetCopyBuildinFileTagsVisible(_copyBuildinFileTagsField);
// 首包文件拷贝选项
_copyBuildinFileOptionField = Root.Q<EnumField>("CopyBuildinFileOption");
@@ -116,7 +119,8 @@ namespace YooAsset.Editor
buildParameters.CompressOption = compressOption;
buildParameters.ClearBuildCacheFiles = clearBuildCache;
buildParameters.UseAssetDependencyDB = useAssetDependencyDB;
buildParameters.EncryptionServices = CreateEncryptionInstance();
buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.ManifestServices = CreateManifestServicesInstance();
BuiltinBuildPipeline pipeline = new BuiltinBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true);

View File

@@ -4,7 +4,7 @@
<ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" />
<ui:Toggle label="Clear Build Cache" name="ClearBuildCache" />
<ui:Toggle label="Use Asset Depend DB" name="UseAssetDependency" />
<ui:VisualElement name="EncryptionContainer" style="height: 24px;" />
<ui:VisualElement name="PopupContainer" style="flex-grow: 1;" />
<uie:EnumField label="Compression" value="Center" name="Compression" />
<uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" />
<uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" />

View File

@@ -74,7 +74,6 @@ namespace YooAsset.Editor
buildParameters.FileNameStyle = fileNameStyle;
buildParameters.BuildinFileCopyOption = buildinFileCopyOption;
buildParameters.BuildinFileCopyParams = buildinFileCopyParams;
buildParameters.EncryptionServices = CreateEncryptionInstance();
EditorSimulateBuildPipeline pipeline = new EditorSimulateBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true);

View File

@@ -16,7 +16,8 @@ namespace YooAsset.Editor
protected TemplateContainer Root;
protected TextField _buildOutputField;
protected TextField _buildVersionField;
protected PopupField<Type> _encryptionField;
protected PopupField<Type> _encryptionServicesField;
protected PopupField<Type> _manifestServicesField;
protected EnumField _outputNameStyleField;
protected EnumField _copyBuildinFileOptionField;
protected TextField _copyBuildinFileTagsField;
@@ -43,8 +44,9 @@ namespace YooAsset.Editor
SetBuildVersionField(_buildVersionField);
// 加密方法
var encryptionContainer = Root.Q("EncryptionContainer");
_encryptionField = CreateEncryptionField(encryptionContainer);
var popupContainer = Root.Q("PopupContainer");
_encryptionServicesField = CreateEncryptionServicesField(popupContainer);
_manifestServicesField = CreateManifestServicesField(popupContainer);
// 输出文件名称样式
_outputNameStyleField = Root.Q<EnumField>("FileNameStyle");
@@ -53,6 +55,7 @@ namespace YooAsset.Editor
// 首包文件拷贝参数
_copyBuildinFileTagsField = Root.Q<TextField>("CopyBuildinFileParam");
SetCopyBuildinFileTagsField(_copyBuildinFileTagsField);
SetCopyBuildinFileTagsVisible(_copyBuildinFileTagsField);
// 首包文件拷贝选项
_copyBuildinFileOptionField = Root.Q<EnumField>("CopyBuildinFileOption");
@@ -108,7 +111,8 @@ namespace YooAsset.Editor
buildParameters.BuildinFileCopyParams = buildinFileCopyParams;
buildParameters.ClearBuildCacheFiles = clearBuildCache;
buildParameters.UseAssetDependencyDB = useAssetDependencyDB;
buildParameters.EncryptionServices = CreateEncryptionInstance();
buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.ManifestServices = CreateManifestServicesInstance();
RawFileBuildPipeline pipeline = new RawFileBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true);

View File

@@ -4,7 +4,7 @@
<ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" />
<ui:Toggle label="Clear Build Cache" name="ClearBuildCache" />
<ui:Toggle label="Use Asset Depend DB" name="UseAssetDependency" />
<ui:VisualElement name="EncryptionContainer" style="height: 24px;" />
<ui:VisualElement name="PopupContainer" style="flex-grow: 1;" />
<uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" />
<uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" />
<ui:TextField picking-mode="Ignore" label="Copy Buildin File Param" name="CopyBuildinFileParam" />

View File

@@ -16,7 +16,8 @@ namespace YooAsset.Editor
protected TemplateContainer Root;
protected TextField _buildOutputField;
protected TextField _buildVersionField;
protected PopupField<Type> _encryptionField;
protected PopupField<Type> _encryptionServicesField;
protected PopupField<Type> _manifestServicesField;
protected EnumField _compressionField;
protected EnumField _outputNameStyleField;
protected EnumField _copyBuildinFileOptionField;
@@ -44,8 +45,9 @@ namespace YooAsset.Editor
SetBuildVersionField(_buildVersionField);
// 加密方法
var encryptionContainer = Root.Q("EncryptionContainer");
_encryptionField = CreateEncryptionField(encryptionContainer);
var popupContainer = Root.Q("PopupContainer");
_encryptionServicesField = CreateEncryptionServicesField(popupContainer);
_manifestServicesField = CreateManifestServicesField(popupContainer);
// 压缩方式选项
_compressionField = Root.Q<EnumField>("Compression");
@@ -58,6 +60,7 @@ namespace YooAsset.Editor
// 首包文件拷贝参数
_copyBuildinFileTagsField = Root.Q<TextField>("CopyBuildinFileParam");
SetCopyBuildinFileTagsField(_copyBuildinFileTagsField);
SetCopyBuildinFileTagsVisible(_copyBuildinFileTagsField);
// 首包文件拷贝选项
_copyBuildinFileOptionField = Root.Q<EnumField>("CopyBuildinFileOption");
@@ -118,7 +121,8 @@ namespace YooAsset.Editor
buildParameters.ClearBuildCacheFiles = clearBuildCache;
buildParameters.UseAssetDependencyDB = useAssetDependencyDB;
buildParameters.BuiltinShadersBundleName = builtinShaderBundleName;
buildParameters.EncryptionServices = CreateEncryptionInstance();
buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.ManifestServices = CreateManifestServicesInstance();
ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true);

View File

@@ -4,7 +4,7 @@
<ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" />
<ui:Toggle label="Clear Build Cache" name="ClearBuildCache" />
<ui:Toggle label="Use Asset Depend DB" name="UseAssetDependency" />
<ui:VisualElement name="EncryptionContainer" style="height: 24px;" />
<ui:VisualElement name="PopupContainer" style="flex-grow: 1;" />
<uie:EnumField label="Compression" value="Center" name="Compression" />
<uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" />
<uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" />

View File

@@ -762,6 +762,7 @@ namespace YooAsset.Editor
elementTop.Add(objectField);
var label = objectField.Q<Label>();
label.style.minWidth = 63;
UIElementsTools.SetObjectFieldShowPath(objectField);
}
// Bottom VisualElement
@@ -851,8 +852,6 @@ namespace YooAsset.Editor
var collector = selectGroup.Collectors[index];
var collectObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(collector.CollectPath);
if (collectObject != null)
collectObject.name = collector.CollectPath;
// 注意:非主资源收集器的标签栏需要被冻结
var textTags = element.Q<TextField>("TextField1");
@@ -885,13 +884,13 @@ namespace YooAsset.Editor
{
collector.CollectPath = AssetDatabase.GetAssetPath(evt.newValue);
collector.CollectorGUID = AssetDatabase.AssetPathToGUID(collector.CollectPath);
objectField1.value.name = collector.CollectPath;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
{
RefreshFoldout(foldout, selectGroup, collector);
}
});
UIElementsTools.RefreshObjectFieldShowPath(objectField1);
// Collector Type
var popupField0 = element.Q<PopupField<string>>("PopupField0");

View File

@@ -177,19 +177,21 @@ namespace YooAsset.Editor
/// </summary>
public string[] GetDependencies(string assetPath, bool recursive)
{
// 注意AssetDatabase.GetDependencies()方法返回结果里会踢出丢失文件!
// 注意AssetDatabase.GetDependencies()方法返回结果里会包含主资源路径!
// 注意:机制上不允许存在未收录的资源
if (_database.ContainsKey(assetPath) == false)
{
throw new Exception($"Fatal : can not found cache info : {assetPath}");
}
var result = new HashSet<string> { assetPath };
var result = new HashSet<string>();
// 注意:递归收集依赖时,依赖列表中包含主资源
if (recursive)
result.Add(assetPath);
// 收集依赖
CollectDependencies(assetPath, assetPath, result, recursive);
// 注意AssetDatabase.GetDependencies保持一致将主资源添加到依赖列表最前面
return result.ToArray();
}
private void CollectDependencies(string parent, string assetPath, HashSet<string> result, bool recursive)
@@ -255,6 +257,7 @@ namespace YooAsset.Editor
}
private DependencyInfo CreateDependencyInfo(string assetPath)
{
// 注意AssetDatabase.GetDependencies()方法返回结果里会踢出丢失文件!
var dependHash = AssetDatabase.GetAssetDependencyHash(assetPath);
var dependAssetPaths = AssetDatabase.GetDependencies(assetPath, false);
var dependGUIDs = new List<string>();

View File

@@ -71,9 +71,10 @@ namespace YooAsset.Editor
public bool UseAssetDependencyDB;
public bool EnableSharePackRule;
public bool SingleReferencedPackAlone;
public string EncryptionClassName;
public string EncryptionServicesClassName;
public string ManifestServicesClassName;
public EFileNameStyle FileNameStyle;
// 引擎参数
public ECompressOption CompressOption;
public bool DisableWriteTypeTree;

View File

@@ -66,7 +66,8 @@ namespace YooAsset.Editor
BindListViewItem("Use Asset Dependency DB", $"{buildReport.Summary.UseAssetDependencyDB}");
BindListViewItem("Enable Share Pack Rule", $"{buildReport.Summary.EnableSharePackRule}");
BindListViewItem("Single Referenced Pack Alone", $"{buildReport.Summary.SingleReferencedPackAlone}");
BindListViewItem("Encryption Class Name", buildReport.Summary.EncryptionClassName);
BindListViewItem("Encryption Services", buildReport.Summary.EncryptionServicesClassName);
BindListViewItem("Manifest Services", buildReport.Summary.ManifestServicesClassName);
BindListViewItem("FileNameStyle", $"{buildReport.Summary.FileNameStyle}");
BindListViewItem("CompressOption", $"{buildReport.Summary.CompressOption}");
BindListViewItem("DisableWriteTypeTree", $"{buildReport.Summary.DisableWriteTypeTree}");

View File

@@ -33,6 +33,67 @@ namespace YooAsset.Editor
}
}
/// <summary>
/// 设置元素显示文本为资源路径
/// </summary>
public static void SetObjectFieldShowPath(ObjectField objectField)
{
string LabelClassName = "unity-object-field-display__label";
var nameLable = objectField.Q<Label>(className: LabelClassName);
if (nameLable == null)
return;
objectField.RegisterValueChangedCallback(evt =>
{
Object obj = evt.newValue;
if (obj == null)
{
nameLable.text = "None (Object)";
return;
}
// 获取资源路径(仅适用于项目资源)
string path = AssetDatabase.GetAssetPath(obj);
if (string.IsNullOrEmpty(path) == false)
{
nameLable.text = path;
}
else
{
nameLable.text = obj.name;
}
});
}
/// <summary>
/// 刷新元素显示文本内容
/// </summary>
public static void RefreshObjectFieldShowPath(ObjectField objectField)
{
string LabelClassName = "unity-object-field-display__label";
var nameLable = objectField.Q<Label>(className: LabelClassName);
if (nameLable == null)
return;
Object obj = objectField.value;
if (obj == null)
{
nameLable.text = "None (Object)";
return;
}
// 获取资源路径(仅适用于项目资源)
string path = AssetDatabase.GetAssetPath(obj);
if (string.IsNullOrEmpty(path) == false)
{
nameLable.text = path;
}
else
{
nameLable.text = obj.name;
}
}
/// <summary>
/// 设置按钮图标
/// </summary>

View File

@@ -106,7 +106,7 @@ namespace YooAsset
}
internal override void InternalWaitForAsyncComplete()
{
//TODO 场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
//注意:场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
InternalUpdate();
}
public override void UnSuspendLoad()

View File

@@ -112,7 +112,7 @@ namespace YooAsset
}
internal override void InternalWaitForAsyncComplete()
{
//TODO 场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
//注意:场景加载不支持异步转同步,为了支持同步加载方法需要实现该方法!
InternalUpdate();
}
public override void UnSuspendLoad()

View File

@@ -88,6 +88,16 @@ namespace YooAsset
/// 自定义参数:解密方法类
/// </summary>
public IDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件服务类
/// </summary>
public ICopyLocalFileServices CopyLocalFileServices { private set; get; }
#endregion
@@ -174,6 +184,14 @@ namespace YooAsset
{
DecryptionServices = (IDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else if (name == FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES)
{
CopyLocalFileServices = (ICopyLocalFileServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");
@@ -196,6 +214,7 @@ namespace YooAsset
_unpackFileSystem.SetParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, InstallClearMode);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, DecryptionServices);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES, CopyLocalFileServices);
_unpackFileSystem.OnCreate(packageName, null);
}
public virtual void OnDestroy()

View File

@@ -11,7 +11,7 @@ namespace YooAsset
/// <summary>
/// 在构建应用程序前自动生成内置资源目录文件。
/// 原理搜索StreamingAssets目录下的所有资源文件然后将这些文件信息写入文件,并存储在Resources目录下
/// 原理搜索StreamingAssets目录下的所有资源文件将这些文件信息写入文件然后在运行时做查询用途
/// </summary>
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
@@ -21,7 +21,7 @@ namespace YooAsset
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists == false)
{
UnityEngine.Debug.LogWarning($"Can not found StreamingAssets root directory : {rootPath}");
Debug.LogWarning($"Can not found StreamingAssets root directory : {rootPath}");
return;
}
@@ -31,10 +31,17 @@ namespace YooAsset
{
string packageName = subDirectory.Name;
string pacakgeDirectory = subDirectory.FullName;
bool result = CreateBuildinCatalogFile(packageName, pacakgeDirectory);
if (result == false)
try
{
throw new System.Exception($"Create package {packageName} catalog file failed ! See the detail error in console !");
bool result = CreateBuildinCatalogFile(null, packageName, pacakgeDirectory);
if (result == false)
{
Debug.LogError($"Create package {packageName} catalog file failed ! See the detail error in console !");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {packageName} catalog file failed ! {ex.Message}");
}
}
}
@@ -42,7 +49,7 @@ namespace YooAsset
/// <summary>
/// 生成包裹的内置资源目录文件
/// </summary>
public static bool CreateBuildinCatalogFile(string packageName, string pacakgeDirectory)
public static bool CreateBuildinCatalogFile(IManifestServices services, string packageName, string pacakgeDirectory)
{
// 获取资源清单版本
string packageVersion;
@@ -70,7 +77,7 @@ namespace YooAsset
}
var binaryData = FileUtility.ReadAllBytes(manifestFilePath);
packageManifest = ManifestTools.DeserializeFromBinary(binaryData);
packageManifest = ManifestTools.DeserializeFromBinary(binaryData, services);
}
// 获取文件名映射关系

View File

@@ -106,10 +106,11 @@ namespace YooAsset
if (_loadCatalogFileOp == null)
{
#if UNITY_EDITOR
/*
// 兼容性初始化
// 说明:内置文件系统在编辑器下运行时需要动态生成
string packageRoot = _fileSystem.FileRoot;
bool result = DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(_fileSystem.PackageName, packageRoot);
bool result = DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(_fileSystem.ManifestServices, _fileSystem.PackageName, packageRoot);
if (result == false)
{
_steps = ESteps.Done;
@@ -117,6 +118,7 @@ namespace YooAsset
Error = $"Create package catalog file failed ! See the detail error in console !";
return;
}
*/
#endif
_loadCatalogFileOp = new LoadBuildinCatalogFileOperation(_fileSystem);

View File

@@ -85,7 +85,7 @@ namespace YooAsset
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_webDataRequestOp.Result);
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -58,7 +58,7 @@ namespace YooAsset
/// <summary>
/// 自定义参数:远程服务接口
/// </summary>
public IRemoteServices RemoteServices { private set; get; } = null;
public IRemoteServices RemoteServices { private set; get; }
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别
@@ -99,6 +99,16 @@ namespace YooAsset
/// 自定义参数:解密方法类
/// </summary>
public IDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件服务类
/// </summary>
public ICopyLocalFileServices CopyLocalFileServices { private set; get; }
#endregion
@@ -221,6 +231,14 @@ namespace YooAsset
{
DecryptionServices = (IDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else if (name == FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES)
{
CopyLocalFileServices = (ICopyLocalFileServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");

View File

@@ -228,9 +228,6 @@ namespace YooAsset
{
if (ExecuteWhileDone())
{
if (_downloadFileOp != null && _downloadFileOp.Status == EOperationStatus.Failed)
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote !");
_steps = ESteps.Done;
break;
}
@@ -360,10 +357,6 @@ namespace YooAsset
{
if (ExecuteWhileDone())
{
//TODO 拷贝本地文件失败也会触发该错误!
if (_downloadFileOp != null && _downloadFileOp.Status == EOperationStatus.Failed)
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote !");
_steps = ESteps.Done;
break;
}

View File

@@ -82,32 +82,43 @@ namespace YooAsset
return oldDownloader;
}
// 设置请求URL
// 获取下载地址
if (string.IsNullOrEmpty(options.ImportFilePath))
{
// 注意:如果是解压文件系统类,这里会返回本地内置文件的下载路径
options.MainURL = _fileSystem.RemoteServices.GetRemoteMainURL(bundle.FileName);
options.FallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(bundle.FileName);
}
else
{
// 注意:把本地文件路径指定为远端下载地址
// 注意:把本地导入文件路径转换为下载器请求地址
options.MainURL = DownloadSystemHelper.ConvertToWWWPath(options.ImportFilePath);
options.FallbackURL = options.MainURL;
}
// 创建新的下载器
DefaultDownloadFileOperation newDownloader;
if (bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize)
bool isRequestLocalFile = DownloadSystemHelper.IsRequestLocalFile(options.MainURL);
if (isRequestLocalFile)
{
newDownloader = new DownloadResumeFileOperation(_fileSystem, bundle, options);
newDownloader = new DownloadLocalFileOperation(_fileSystem, bundle, options);
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
}
else
{
newDownloader = new DownloadNormalFileOperation(_fileSystem, bundle, options);
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
if (bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize)
{
newDownloader = new DownloadResumeFileOperation(_fileSystem, bundle, options);
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
}
else
{
newDownloader = new DownloadNormalFileOperation(_fileSystem, bundle, options);
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
}
}
return newDownloader;
}

View File

@@ -0,0 +1,221 @@
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal class DownloadLocalFileOperation : DefaultDownloadFileOperation
{
private readonly DefaultCacheFileSystem _fileSystem;
private VerifyTempFileOperation _verifyOperation;
private string _tempFilePath;
private ESteps _steps = ESteps.None;
internal DownloadLocalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle, options)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_tempFilePath = _fileSystem.GetTempFilePath(Bundle);
_steps = ESteps.CheckExists;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 检测文件是否存在
if (_steps == ESteps.CheckExists)
{
if (_fileSystem.Exists(Bundle))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
if (_fileSystem.CopyLocalFileServices != null)
_steps = ESteps.CopyBuildinBundle;
else
_steps = ESteps.CreateRequest;
}
}
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
FileUtility.CreateFileDirectory(_tempFilePath);
// 删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
// 获取请求地址
_requestURL = GetRequestURL();
// 重置请求
ResetRequestFiled();
// 创建下载器
CreateWebRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes;
Progress = DownloadProgress;
if (_webRequest.isDone == false)
{
CheckRequestTimeout();
return;
}
// 检查网络错误
if (CheckRequestResult())
_steps = ESteps.VerifyTempFile;
else
_steps = ESteps.TryAgain;
// 注意:最终释放请求器
DisposeWebRequest();
}
// 拷贝内置文件
if (_steps == ESteps.CopyBuildinBundle)
{
FileUtility.CreateFileDirectory(_tempFilePath);
// 删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
// 获取请求地址
_requestURL = GetRequestURL();
try
{
//TODO 团结引擎,在某些机型(红米),拷贝包内文件会小概率失败!需要借助其它方式来拷贝包内文件。
var localFileInfo = new LocalFileInfo();
localFileInfo.PackageName = _fileSystem.PackageName;
localFileInfo.BundleName = Bundle.BundleName;
localFileInfo.SourceFileURL = _requestURL;
_fileSystem.CopyLocalFileServices.CopyFile(localFileInfo, _tempFilePath);
if (File.Exists(_tempFilePath))
{
DownloadProgress = 1f;
DownloadedBytes = Bundle.FileSize;
Progress = DownloadProgress;
_steps = ESteps.VerifyTempFile;
}
else
{
Error = $"Failed copy local file : {_requestURL}";
_steps = ESteps.TryAgain;
}
}
catch (System.Exception ex)
{
Error = $"Failed copy local file : {ex.Message}";
_steps = ESteps.TryAgain;
}
}
// 验证下载文件
if (_steps == ESteps.VerifyTempFile)
{
var element = new TempFileElement(_tempFilePath, Bundle.FileCRC, Bundle.FileSize);
_verifyOperation = new VerifyTempFileOperation(element);
_verifyOperation.StartOperation();
AddChildOperation(_verifyOperation);
_steps = ESteps.CheckVerifyTempFile;
}
// 等待验证完成
if (_steps == ESteps.CheckVerifyTempFile)
{
if (IsWaitForAsyncComplete)
_verifyOperation.WaitForAsyncComplete();
_verifyOperation.UpdateOperation();
if (_verifyOperation.IsDone == false)
return;
if (_verifyOperation.Status == EOperationStatus.Succeed)
{
if (_fileSystem.WriteCacheBundleFile(Bundle, _tempFilePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{_fileSystem.GetType().FullName} failed to write file !";
YooLogger.Error(Error);
}
}
else
{
_steps = ESteps.TryAgain;
Error = _verifyOperation.Error;
}
// 注意:验证完成后直接删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
//TODO 拷贝本地文件失败后不再尝试!
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
}
}
internal override void InternalAbort()
{
_steps = ESteps.Done;
DisposeWebRequest();
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
//TODO 等待导入或解压本地文件完毕,该操作会挂起主线程!
InternalUpdate();
if (IsDone)
break;
// 短暂休眠避免完全卡死
System.Threading.Thread.Sleep(1);
}
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
//注意引擎底层会自动调用Abort方法
_webRequest.Dispose();
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -8,7 +8,6 @@ namespace YooAsset
{
private readonly DefaultCacheFileSystem _fileSystem;
private VerifyTempFileOperation _verifyOperation;
private bool _isReuqestLocalFile;
private string _tempFilePath;
private ESteps _steps = ESteps.None;
@@ -18,7 +17,6 @@ namespace YooAsset
}
internal override void InternalStart()
{
_isReuqestLocalFile = DownloadSystemHelper.IsRequestLocalFile(Options.MainURL);
_tempFilePath = _fileSystem.GetTempFilePath(Bundle);
_steps = ESteps.CheckExists;
}
@@ -133,15 +131,6 @@ namespace YooAsset
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
//TODO 拷贝本地文件失败后不再尝试!
if (_isReuqestLocalFile)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
if (FailedTryAgain <= 0)
{
Status = EOperationStatus.Failed;
@@ -168,20 +157,17 @@ namespace YooAsset
{
while (true)
{
//TODO 如果是导入或解压本地文件,执行等待完毕
if (_isReuqestLocalFile)
if (ExecuteWhileDone())
{
InternalUpdate();
if (IsDone)
break;
}
else
{
if (ExecuteWhileDone())
//TODO 尝试同步加载远端的资源文件失败
if (Status == EOperationStatus.Failed)
{
_steps = ESteps.Done;
break;
YooLogger.Error($"Try load bundle {Bundle.BundleName} from remote !");
YooLogger.Error($"The load remote bundle url : {_requestURL}");
}
_steps = ESteps.Done;
break;
}
}
}

View File

@@ -9,19 +9,16 @@ namespace YooAsset
private readonly DefaultCacheFileSystem _fileSystem;
private DownloadHandlerFileRange _downloadHandle;
private VerifyTempFileOperation _verifyOperation;
private bool _isReuqestLocalFile;
private long _fileOriginLength = 0;
private string _tempFilePath;
private ESteps _steps = ESteps.None;
internal DownloadResumeFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle, options)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_isReuqestLocalFile = DownloadSystemHelper.IsRequestLocalFile(Options.MainURL);
_tempFilePath = _fileSystem.GetTempFilePath(Bundle);
_steps = ESteps.CheckExists;
}
@@ -152,15 +149,6 @@ namespace YooAsset
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
//TODO 拷贝本地文件失败后不再尝试!
if (_isReuqestLocalFile)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
if (FailedTryAgain <= 0)
{
Status = EOperationStatus.Failed;
@@ -187,20 +175,17 @@ namespace YooAsset
{
while (true)
{
//TODO 如果是导入或解压本地文件,执行等待完毕
if (_isReuqestLocalFile)
if (ExecuteWhileDone())
{
InternalUpdate();
if (IsDone)
break;
}
else
{
if (ExecuteWhileDone())
//TODO 尝试同步加载远端的资源文件失败
if (Status == EOperationStatus.Failed)
{
_steps = ESteps.Done;
break;
YooLogger.Error($"Try load bundle {Bundle.BundleName} from remote !");
YooLogger.Error($"The load remote bundle url : {_requestURL}");
}
_steps = ESteps.Done;
break;
}
}
}

View File

@@ -75,7 +75,7 @@ namespace YooAsset
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_fileData);
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _fileData);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -71,10 +71,13 @@ namespace YooAsset
{
while (true)
{
//TODO 等待子线程验证文件完毕,该操作会挂起主线程
//TODO 等待子线程验证文件完毕,该操作会挂起主线程
InternalUpdate();
if (IsDone)
break;
// 短暂休眠避免完全卡死
System.Threading.Thread.Sleep(1);
}
}

View File

@@ -75,7 +75,7 @@ namespace YooAsset
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_fileData);
_deserializer = new DeserializeManifestOperation(null, _fileData);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -3,11 +3,6 @@ namespace YooAsset
{
internal class DefaultUnpackFileSystemDefine
{
/// <summary>
/// 文件系统的优先级
/// </summary>
public const int DefaultPriority = 11;
/// <summary>
/// 保存的资源文件的文件夹名称
/// </summary>

View File

@@ -46,12 +46,17 @@ namespace YooAsset
/// <summary>
/// 自定义参数:跨域下载服务接口
/// </summary>
public IRemoteServices RemoteServices { private set; get; } = null;
public IRemoteServices RemoteServices { private set; get; }
/// <summary>
/// 自定义参数:解密方法类
/// </summary>
public IWebDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
#endregion
@@ -111,6 +116,10 @@ namespace YooAsset
{
DecryptionServices = (IWebDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");

View File

@@ -88,7 +88,7 @@ namespace YooAsset
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_webDataRequestOp.Result);
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -61,6 +61,11 @@ namespace YooAsset
/// 自定义参数:解密方法类
/// </summary>
public IWebDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
#endregion
@@ -116,6 +121,10 @@ namespace YooAsset
{
DecryptionServices = (IWebDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");

View File

@@ -33,10 +33,11 @@ namespace YooAsset
if (_loadCatalogFileOp == null)
{
#if UNITY_EDITOR
/*
// 兼容性初始化
// 说明:内置文件系统在编辑器下运行时需要动态生成
string packageRoot = _fileSystem.FileRoot;
bool result = DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(_fileSystem.PackageName, packageRoot);
bool result = DefaultBuildinFileSystemBuild.CreateBuildinCatalogFile(_fileSystem.ManifestServices, _fileSystem.PackageName, packageRoot);
if (result == false)
{
_steps = ESteps.Done;
@@ -44,6 +45,7 @@ namespace YooAsset
Error = $"Create package catalog file failed ! See the detail error in console !";
return;
}
*/
#endif
_loadCatalogFileOp = new LoadWebServerCatalogFileOperation(_fileSystem);

View File

@@ -85,7 +85,7 @@ namespace YooAsset
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_webDataRequestOp.Result);
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -7,6 +7,7 @@ namespace YooAsset
public const string INSTALL_CLEAR_MODE = "INSTALL_CLEAR_MODE";
public const string REMOTE_SERVICES = "REMOTE_SERVICES";
public const string DECRYPTION_SERVICES = "DECRYPTION_SERVICES";
public const string MANIFEST_SERVICES = "MANIFEST_SERVICES";
public const string APPEND_FILE_EXTENSION = "APPEND_FILE_EXTENSION";
public const string DISABLE_CATALOG_FILE = "DISABLE_CATALOG_FILE";
public const string DISABLE_UNITY_WEB_CACHE = "DISABLE_UNITY_WEB_CACHE";
@@ -18,5 +19,6 @@ namespace YooAsset
public const string ASYNC_SIMULATE_MAX_FRAME = "ASYNC_SIMULATE_MAX_FRAME";
public const string COPY_BUILDIN_PACKAGE_MANIFEST = "COPY_BUILDIN_PACKAGE_MANIFEST";
public const string COPY_BUILDIN_PACKAGE_MANIFEST_DEST_ROOT = "COPY_BUILDIN_PACKAGE_MANIFEST_DEST_ROOT";
public const string COPY_LOCAL_FILE_SERVICES = "COPY_LOCAL_FILE_SERVICES";
}
}

View File

@@ -24,7 +24,7 @@ namespace YooAsset
public string FallbackURL { set; get; }
/// <summary>
/// 导入的本地文件路径
/// 拷贝的本地文件路径
/// </summary>
public string ImportFilePath { set; get; }

View File

@@ -11,6 +11,7 @@ namespace YooAsset
CheckExists,
CreateRequest,
CheckRequest,
CopyBuildinBundle,
VerifyTempFile,
CheckVerifyTempFile,
TryAgain,

View File

@@ -42,6 +42,11 @@ namespace YooAsset
/// 同时加载Bundle文件的最大并发数
/// </summary>
public int BundleLoadingMaxConcurrency = int.MaxValue;
/// <summary>
/// WebGL平台强制同步加载资源对象
/// </summary>
public bool WebGLForceSyncLoadAsset = false;
}
/// <summary>

View File

@@ -260,8 +260,11 @@ namespace YooAsset
StartOperation();
}
IsWaitForAsyncComplete = true;
InternalWaitForAsyncComplete();
if (IsWaitForAsyncComplete == false)
{
IsWaitForAsyncComplete = true;
InternalWaitForAsyncComplete();
}
}
#region

View File

@@ -14,7 +14,7 @@ namespace YooAsset
Done,
}
private readonly ResourceManager _resourceManager;
private readonly ResourceManager _resManager;
private readonly List<ProviderOperation> _providers = new List<ProviderOperation>(100);
private readonly List<ProviderOperation> _removeList = new List<ProviderOperation>(100);
private FSLoadBundleOperation _loadBundleOp;
@@ -53,7 +53,7 @@ namespace YooAsset
internal LoadBundleFileOperation(ResourceManager resourceManager, BundleInfo bundleInfo)
{
_resourceManager = resourceManager;
_resManager = resourceManager;
LoadBundleInfo = bundleInfo;
}
internal override void InternalStart()
@@ -73,7 +73,7 @@ namespace YooAsset
}
else
{
if (_resourceManager.BundleLoadingIsBusy())
if (_resManager.BundleLoadingIsBusy())
return;
_steps = ESteps.LoadBundleFile;
}
@@ -83,7 +83,7 @@ namespace YooAsset
{
if (_loadBundleOp == null)
{
_resourceManager.BundleLoadingCounter++;
_resManager.BundleLoadingCounter++;
_loadBundleOp = LoadBundleInfo.LoadBundleFile();
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
@@ -121,7 +121,7 @@ namespace YooAsset
}
// 统计计数减少
_resourceManager.BundleLoadingCounter--;
_resManager.BundleLoadingCounter--;
}
}
internal override void InternalWaitForAsyncComplete()
@@ -191,7 +191,7 @@ namespace YooAsset
{
foreach (var bundleID in LoadBundleInfo.Bundle.ReferenceBundleIDs)
{
if (_resourceManager.CheckBundleDestroyed(bundleID) == false)
if (_resManager.CheckBundleDestroyed(bundleID) == false)
return false;
}
}
@@ -233,7 +233,7 @@ namespace YooAsset
// 移除资源提供者
if (_removeList.Count > 0)
{
_resourceManager.RemoveBundleProviders(_removeList);
_resManager.RemoveBundleProviders(_removeList);
_removeList.Clear();
}
}

View File

@@ -15,6 +15,11 @@ namespace YooAsset
_loadAllAssetsOp = BundleResultObject.LoadAllAssetsAsync(MainAssetInfo);
_loadAllAssetsOp.StartOperation();
AddChildOperation(_loadAllAssetsOp);
#if UNITY_WEBGL
if (_resManager.WebGLForceSyncLoadAsset())
_loadAllAssetsOp.WaitForAsyncComplete();
#endif
}
if (IsWaitForAsyncComplete)

View File

@@ -15,6 +15,11 @@ namespace YooAsset
_loadAssetOp = BundleResultObject.LoadAssetAsync(MainAssetInfo);
_loadAssetOp.StartOperation();
AddChildOperation(_loadAssetOp);
#if UNITY_WEBGL
if (_resManager.WebGLForceSyncLoadAsset())
_loadAssetOp.WaitForAsyncComplete();
#endif
}
if (IsWaitForAsyncComplete)

View File

@@ -68,13 +68,14 @@ namespace YooAsset
private ESteps _steps = ESteps.None;
protected readonly ResourceManager _resManager;
private readonly LoadBundleFileOperation _mainBundleLoader;
private readonly List<LoadBundleFileOperation> _bundleLoaders = new List<LoadBundleFileOperation>(10);
private readonly HashSet<HandleBase> _handles = new HashSet<HandleBase>();
public ProviderOperation(ResourceManager manager, string providerGUID, AssetInfo assetInfo)
{
_resManager = manager;
ProviderGUID = providerGUID;
MainAssetInfo = assetInfo;

View File

@@ -15,6 +15,11 @@ namespace YooAsset
_loadSubAssetsOp = BundleResultObject.LoadSubAssetsAsync(MainAssetInfo);
_loadSubAssetsOp.StartOperation();
AddChildOperation(_loadSubAssetsOp);
#if UNITY_WEBGL
if (_resManager.WebGLForceSyncLoadAsset())
_loadSubAssetsOp.WaitForAsyncComplete();
#endif
}
if (IsWaitForAsyncComplete)

View File

@@ -15,6 +15,7 @@ namespace YooAsset
private long _sceneCreateIndex = 0;
private IBundleQuery _bundleQuery;
private int _bundleLoadingMaxConcurrency;
private bool _webGLForceSyncLoadAsset;
/// <summary>
/// 所属包裹
@@ -43,6 +44,7 @@ namespace YooAsset
public void Initialize(InitializeParameters parameters, IBundleQuery bundleServices)
{
_bundleLoadingMaxConcurrency = parameters.BundleLoadingMaxConcurrency;
_webGLForceSyncLoadAsset = parameters.WebGLForceSyncLoadAsset;
_bundleQuery = bundleServices;
SceneManager.sceneUnloaded += OnSceneUnloaded;
}
@@ -321,6 +323,10 @@ namespace YooAsset
{
return BundleLoadingCounter >= _bundleLoadingMaxConcurrency;
}
internal bool WebGLForceSyncLoadAsset()
{
return _webGLForceSyncLoadAsset;
}
private LoadBundleFileOperation CreateBundleFileLoaderInternal(BundleInfo bundleInfo)
{

View File

@@ -44,7 +44,7 @@ namespace YooAsset
/// <summary>
/// 序列化(二进制文件)
/// </summary>
public static void SerializeToBinary(string savePath, PackageManifest manifest)
public static void SerializeToBinary(string savePath, PackageManifest manifest, IManifestServices services)
{
using (FileStream fs = new FileStream(savePath, FileMode.Create))
{
@@ -96,9 +96,20 @@ namespace YooAsset
buffer.WriteInt32Array(packageBundle.DependBundleIDs);
}
// 写入文件流
buffer.WriteToStream(fs);
fs.Flush();
// 清单处理操作
if (services != null)
{
var tempBytes = buffer.GetBytes();
var resultBytes = services.ProcessManifest(tempBytes);
fs.Write(resultBytes, 0, resultBytes.Length);
fs.Flush();
}
else
{
// 写入文件流
buffer.WriteToStream(fs);
fs.Flush();
}
}
}
@@ -113,10 +124,19 @@ namespace YooAsset
/// <summary>
/// 反序列化(二进制文件)
/// </summary>
public static PackageManifest DeserializeFromBinary(byte[] binaryData)
public static PackageManifest DeserializeFromBinary(byte[] binaryData, IManifestServices services)
{
// 创建缓存器
BufferReader buffer = new BufferReader(binaryData);
BufferReader buffer;
if (services != null)
{
var resultBytes = services.RestoreManifest(binaryData);
buffer = new BufferReader(resultBytes);
}
else
{
buffer = new BufferReader(binaryData);
}
// 读取文件标记
uint fileSign = buffer.ReadUInt32();

View File

@@ -10,6 +10,7 @@ namespace YooAsset
private enum ESteps
{
None,
RestoreFileData,
DeserializeFileHeader,
PrepareAssetList,
DeserializeAssetList,
@@ -19,7 +20,9 @@ namespace YooAsset
Done,
}
private readonly BufferReader _buffer;
private readonly IManifestServices _services;
private byte[] _sourceData;
private BufferReader _buffer;
private int _packageAssetCount;
private int _packageBundleCount;
private int _progressTotalValue;
@@ -30,13 +33,14 @@ namespace YooAsset
/// </summary>
public PackageManifest Manifest { private set; get; }
public DeserializeManifestOperation(byte[] binaryData)
public DeserializeManifestOperation(IManifestServices services, byte[] binaryData)
{
_buffer = new BufferReader(binaryData);
_services = services;
_sourceData = binaryData;
}
internal override void InternalStart()
{
_steps = ESteps.DeserializeFileHeader;
_steps = ESteps.RestoreFileData;
}
internal override void InternalUpdate()
{
@@ -45,6 +49,19 @@ namespace YooAsset
try
{
if (_steps == ESteps.RestoreFileData)
{
if (_services != null)
{
var resultData = _services.RestoreManifest(_sourceData);
if (resultData != null)
_sourceData = resultData;
}
_buffer = new BufferReader(_sourceData);
_steps = ESteps.DeserializeFileHeader;
}
if (_steps == ESteps.DeserializeFileHeader)
{
if (_buffer.IsValid == false)

View File

@@ -0,0 +1,30 @@

namespace YooAsset
{
public struct LocalFileInfo
{
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 源文件请求地址
/// </summary>
public string SourceFileURL;
}
/// <summary>
/// 本地文件拷贝服务类
/// 备注:包体内文件拷贝,沙盒内文件导入都会触发该服务!
/// </summary>
public interface ICopyLocalFileServices
{
void CopyFile(LocalFileInfo sourceFileInfo, string destFilePath);
}
}

View File

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

View File

@@ -42,23 +42,23 @@ namespace YooAsset
public interface IDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
/// 同步方式获取解密的资源包
/// </summary>
DecryptResult LoadAssetBundle(DecryptFileInfo fileInfo);
/// <summary>
/// 异步方式获取解密的资源包对象
/// 异步方式获取解密的资源包
/// </summary>
DecryptResult LoadAssetBundleAsync(DecryptFileInfo fileInfo);
/// <summary>
/// 后备方式获取解密的资源包对象
/// 后备方式获取解密的资源包
/// 注意:当正常解密方法失败后,会触发后备加载!
/// 说明建议通过LoadFromMemory()方法加载资源对象作为保底机制。
/// 说明建议通过LoadFromMemory()方法加载资源作为保底机制。
/// issues : https://github.com/tuyoogame/YooAsset/issues/562
/// </summary>
DecryptResult LoadAssetBundleFallback(DecryptFileInfo fileInfo);
/// <summary>
/// 获取解密的字节数据
/// </summary>

View File

@@ -1,6 +1,18 @@

namespace YooAsset
{
public struct EncryptFileInfo
{
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 文件路径
/// </summary>
public string FileLoadPath;
}
public struct EncryptResult
{
/// <summary>
@@ -14,19 +26,6 @@ namespace YooAsset
public byte[] EncryptedData;
}
public struct EncryptFileInfo
{
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 文件路径
/// </summary>
public string FileLoadPath;
}
public interface IEncryptionServices
{
EncryptResult Encrypt(EncryptFileInfo fileInfo);

View File

@@ -0,0 +1,19 @@

namespace YooAsset
{
/// <summary>
/// 资源清单文件处理服务接口
/// </summary>
public interface IManifestServices
{
/// <summary>
/// 处理资源清单(压缩和加密)
/// </summary>
byte[] ProcessManifest(byte[] fileData);
/// <summary>
/// 还原资源清单(解压和解密)
/// </summary>
byte[] RestoreManifest(byte[] fileData);
}
}

View File

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

View File

@@ -36,6 +36,16 @@ namespace YooAsset
_index = 0;
}
/// <summary>
/// 获取有效数据
/// </summary>
public byte[] GetBytes()
{
byte[] newArray = new byte[_index];
Buffer.BlockCopy(_buffer, 0, newArray, 0, _index);
return newArray;
}
/// <summary>
/// 将有效数据写入文件流
/// </summary>

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b1774501eb8484d47b6c9d61585b4cd4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
internal class ClearBuildCacheWindow
{
[MenuItem("Tools/Clear Build Cache", false, 2)]
public static void OpenWindow()
{
// 清空SBP构建缓存
UnityEditor.Build.Pipeline.Utilities.BuildCache.PurgeCache(false);
// 删除AssetDependDB文件
string projectPath = YooAsset.Editor.EditorTools.GetProjectPath();
string databaseFilePath = $"{projectPath}/Library/AssetDependencyDB";
if (File.Exists(databaseFilePath))
{
File.Delete(databaseFilePath);
}
}
}
}

View File

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

View File

@@ -106,11 +106,11 @@ namespace YooAsset.Editor
// 加载补丁清单1
byte[] bytesData1 = FileUtility.ReadAllBytes(_manifestPath1);
PackageManifest manifest1 = ManifestTools.DeserializeFromBinary(bytesData1);
PackageManifest manifest1 = ManifestTools.DeserializeFromBinary(bytesData1, null); //TODO 自行处理解密
// 加载补丁清单1
byte[] bytesData2 = FileUtility.ReadAllBytes(_manifestPath2);
PackageManifest manifest2 = ManifestTools.DeserializeFromBinary(bytesData2);
PackageManifest manifest2 = ManifestTools.DeserializeFromBinary(bytesData2, null); //TODO 自行处理解密
// 拷贝文件列表
foreach (var bundle2 in manifest2.BundleList)

View File

@@ -71,7 +71,7 @@ namespace YooAsset.Editor
// 加载补丁清单
byte[] bytesData = FileUtility.ReadAllBytes(manifestFilePath);
PackageManifest manifest = ManifestTools.DeserializeFromBinary(bytesData);
PackageManifest manifest = ManifestTools.DeserializeFromBinary(bytesData, null); //TODO 自行处理解密
// 拷贝文件列表
int fileCount = 0;

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using YooAsset;
/// <summary>
/// 获取包体里的内置资源清单版本
/// </summary>
public class GetBuildinPackageVersionOperation : GameAsyncOperation
{
private enum ESteps
{
None,
GetPackageVersion,
Done,
}
private readonly string _packageName;
private UnityWebTextRequestOperation _versionFileRequestOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 内置资源清单版本
/// </summary>
public string PackageVersion { private set; get; }
public GetBuildinPackageVersionOperation(string packageName)
{
_packageName = packageName;
}
protected override void OnStart()
{
_steps = ESteps.GetPackageVersion;
}
protected override void OnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetPackageVersion)
{
if (_versionFileRequestOp == null)
{
string filePath = GetBuildinPackageVersionFilePath();
string url = DownloadSystemHelper.ConvertToWWWPath(filePath);
_versionFileRequestOp = new UnityWebTextRequestOperation(url);
OperationSystem.StartOperation(_packageName, _versionFileRequestOp);
}
if (_versionFileRequestOp.IsDone == false)
return;
if (_versionFileRequestOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
PackageVersion = _versionFileRequestOp.Result;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _versionFileRequestOp.Error;
}
}
}
protected override void OnAbort()
{
}
private string GetBuildinYooRoot()
{
return YooAssetSettingsData.GetYooDefaultBuildinRoot();
}
private string GetBuildinPackageVersionFilePath()
{
string fileRoot = GetBuildinYooRoot();
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName);
return PathUtility.Combine(fileRoot, _packageName, fileName);
}
}

View File

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

View File

@@ -92,7 +92,7 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_webDataRequestOp.Result);
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -103,6 +103,11 @@ internal class TiktokFileSystem : IFileSystem
/// 自定义参数:解密方法类
/// </summary>
public IWebDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
#endregion
@@ -161,6 +166,10 @@ internal class TiktokFileSystem : IFileSystem
{
DecryptionServices = (IWebDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");

View File

@@ -92,7 +92,7 @@ internal class LoadWechatPackageManifestOperation : AsyncOperationBase
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_webDataRequestOp.Result);
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}

View File

@@ -104,6 +104,11 @@ internal class WechatFileSystem : IFileSystem
/// 自定义参数:解密方法类
/// </summary>
public IWebDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
#endregion
@@ -176,6 +181,10 @@ internal class WechatFileSystem : IFileSystem
{
DecryptionServices = (IWebDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");

View File

@@ -71,7 +71,8 @@ public static class TestPackageBuilder
buildParameters.ClearBuildCacheFiles = true;
buildParameters.UseAssetDependencyDB = true;
buildParameters.BuiltinShadersBundleName = builtinShaderBundleName;
buildParameters.EncryptionServices = new FileStreamTestEncryption();
buildParameters.EncryptionServices = new TestFileStreamEncryption();
buildParameters.ManifestServices = new TestProcessManifest();
var pipeline = new ScriptableBuildPipeline();
BuildResult buildResult = pipeline.Run(buildParameters, false);
@@ -108,7 +109,8 @@ public static class TestPackageBuilder
buildParameters.CompressOption = ECompressOption.LZ4;
buildParameters.ClearBuildCacheFiles = true;
buildParameters.UseAssetDependencyDB = true;
buildParameters.EncryptionServices = new FileStreamTestEncryption();
buildParameters.EncryptionServices = new TestFileStreamEncryption();
buildParameters.ManifestServices = new TestProcessManifest();
var pipeline = new BuiltinBuildPipeline();
BuildResult buildResult = pipeline.Run(buildParameters, false);

View File

@@ -168,14 +168,14 @@ public class T0_InitYooAssets : IPrebuildSetup, IPostBuildCleanup
collector1.CollectPath = "";
collector1.CollectorGUID = "e082d492b9da65e499cee3495be3645d"; //TestRes3/music目录
collector1.CollectorType = YooAsset.Editor.ECollectorType.MainAssetCollector;
collector1.PackRuleName = nameof(YooAsset.Editor.PackDirectory);
collector1.PackRuleName = nameof(YooAsset.Editor.PackSeparately);
YooAsset.Editor.AssetBundleCollectorSettingData.CreateCollector(referenceGroup, collector1);
var collector2 = new YooAsset.Editor.AssetBundleCollector();
collector2.CollectPath = "";
collector2.CollectorGUID = "8c5a1726d94498e4cbe30f5f510cc796"; //TestRes3/prefab目录
collector2.CollectorType = YooAsset.Editor.ECollectorType.MainAssetCollector;
collector2.PackRuleName = nameof(YooAsset.Editor.PackDirectory);
collector2.PackRuleName = nameof(YooAsset.Editor.PackSeparately);
YooAsset.Editor.AssetBundleCollectorSettingData.CreateCollector(referenceGroup, collector2);
}
}

View File

@@ -47,7 +47,7 @@ public class T2_TestBuldinFileSystem : IPrebuildSetup, IPostBuildCleanup
[UnityTest]
public IEnumerator A_InitializePackage()
{
// 初始化资源包
// 初始化资源包 ASSET_BUNDLE
{
string packageRoot = string.Empty;
#if UNITY_EDITOR
@@ -60,8 +60,11 @@ public class T2_TestBuldinFileSystem : IPrebuildSetup, IPostBuildCleanup
// 初始化资源包
var initParams = new OfflinePlayModeParameters();
var decryption = new FileStreamTestDecryption();
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(decryption, packageRoot);
var fileDecryption = new TestFileStreamDecryption();
var manifestProcess = new TestProcessManifest();
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(fileDecryption, packageRoot);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.DISABLE_CATALOG_FILE, true);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.MANIFEST_SERVICES, manifestProcess);
var initializeOp = package.InitializeAsync(initParams);
yield return initializeOp;
if (initializeOp.Status != EOperationStatus.Succeed)
@@ -83,7 +86,7 @@ public class T2_TestBuldinFileSystem : IPrebuildSetup, IPostBuildCleanup
Assert.AreEqual(EOperationStatus.Succeed, updateManifestOp.Status);
}
// 初始化资源包
// 初始化资源包 RAW_BUNDLE
{
string packageRoot = string.Empty;
#if UNITY_EDITOR
@@ -98,6 +101,7 @@ public class T2_TestBuldinFileSystem : IPrebuildSetup, IPostBuildCleanup
var initParams = new OfflinePlayModeParameters();
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(null, packageRoot);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, true);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.DISABLE_CATALOG_FILE, true);
var initializeOp = package.InitializeAsync(initParams);
yield return initializeOp;
if (initializeOp.Status != EOperationStatus.Succeed)

View File

@@ -13,9 +13,22 @@ public class TestBundleEncryption
ResourcePackage package = YooAssets.GetPackage(TestDefine.AssetBundlePackageName);
Assert.IsNotNull(package);
// 加载音乐播放预制体
// 异步加载音乐播放预制体
{
var assetHandle = package.LoadAssetAsync<GameObject>("prefab_audio");
var assetHandle = package.LoadAssetAsync<GameObject>("prefab_audioA");
yield return assetHandle;
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
var go = assetHandle.InstantiateSync(Vector3.zero, Quaternion.identity);
Assert.IsNotNull(go);
var audioSource = go.GetComponent<AudioSource>();
Assert.IsNotNull(audioSource.clip);
}
// 同步加载音乐播放预制体
{
var assetHandle = package.LoadAssetSync<GameObject>("prefab_audioB");
yield return assetHandle;
Assert.AreEqual(EOperationStatus.Succeed, assetHandle.Status);
@@ -34,7 +47,7 @@ public class TestBundleEncryption
/// <summary>
/// 文件流加密方式
/// </summary>
public class FileStreamTestEncryption : IEncryptionServices
public class TestFileStreamEncryption : IEncryptionServices
{
public EncryptResult Encrypt(EncryptFileInfo fileInfo)
{
@@ -64,7 +77,7 @@ public class FileStreamTestEncryption : IEncryptionServices
/// <summary>
/// 文件偏移加密方式
/// </summary>
public class FileOffsetTestEncryption : IEncryptionServices
public class TestFileOffsetEncryption : IEncryptionServices
{
public EncryptResult Encrypt(EncryptFileInfo fileInfo)
{
@@ -119,7 +132,7 @@ public class BundleStream : FileStream
/// <summary>
/// 资源文件流解密类
/// </summary>
public class FileStreamTestDecryption : IDecryptionServices
public class TestFileStreamDecryption : IDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
@@ -180,7 +193,7 @@ public class FileStreamTestDecryption : IDecryptionServices
/// <summary>
/// 资源文件偏移解密类
/// </summary>
public class FileOffsetTestDecryption : IDecryptionServices
public class TestFileOffsetDecryption : IDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
@@ -240,7 +253,7 @@ public class FileOffsetTestDecryption : IDecryptionServices
/// WebGL平台解密类
/// 注意WebGL平台支持内存解密
/// </summary>
public class WebFileStreamTestDecryption : IWebDecryptionServices
public class TestWebFileStreamDecryption : IWebDecryptionServices
{
public WebDecryptResult LoadAssetBundle(WebDecryptFileInfo fileInfo)
{

View File

@@ -0,0 +1,55 @@
using System;
using System.IO;
using System.Text;
using System.Collections;
using UnityEngine;
using NUnit.Framework;
using YooAsset;
public class TestProcessManifest : IManifestServices
{
public byte[] ProcessManifest(byte[] fileData)
{
return XorProcess(fileData, "YOO");
}
public byte[] RestoreManifest(byte[] fileData)
{
return XorProcess(fileData, "YOO");
}
/// <summary>
/// 使用异或加密/解密字节数组
/// </summary>
/// <param name="data">输入数据</param>
/// <param name="key">加密密钥</param>
/// <returns>处理后的字节数组</returns>
public static byte[] XorProcess(byte[] data, byte[] key)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
if (key == null || key.Length == 0)
throw new ArgumentException("Key cannot be null or empty");
byte[] result = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
// 循环使用密钥中的字节
result[i] = (byte)(data[i] ^ key[i % key.Length]);
}
return result;
}
/// <summary>
/// 使用字符串密钥进行异或处理(自动转换编码)
/// </summary>
/// <param name="data">输入数据</param>
/// <param name="key">字符串密钥</param>
/// <returns>处理后的字节数组</returns>
public static byte[] XorProcess(byte[] data, string key)
{
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key);
return XorProcess(data, keyBytes);
}
}

View File

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

View File

@@ -0,0 +1,59 @@
fileFormatVersion: 2
guid: 502e4faa60c5fc441a6a8ae9a61fbf35
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 2
sampleRateSetting: 0
sampleRateOverride: 0
compressionFormat: 1
quality: 0.5
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides:
1:
serializedVersion: 2
loadType: 2
sampleRateSetting: 0
sampleRateOverride: 0
compressionFormat: 1
quality: 0.5
conversionMode: 0
preloadAudioData: 1
4:
serializedVersion: 2
loadType: 2
sampleRateSetting: 0
sampleRateOverride: 0
compressionFormat: 1
quality: 0.5
conversionMode: 0
preloadAudioData: 1
7:
serializedVersion: 2
loadType: 2
sampleRateSetting: 0
sampleRateOverride: 0
compressionFormat: 1
quality: 0.5
conversionMode: 0
preloadAudioData: 1
13:
serializedVersion: 2
loadType: 2
sampleRateSetting: 2
sampleRateOverride: 44100
compressionFormat: 7
quality: 0.5
conversionMode: 0
preloadAudioData: 1
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -12,7 +12,7 @@ GameObject:
- component: {fileID: 8364371343008149393}
- component: {fileID: 7423861191467597400}
m_Layer: 0
m_Name: prefab_audio
m_Name: prefab_audioA
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0

View File

@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3749121449083481702
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1740794871874781600}
- component: {fileID: 8364371343008149393}
- component: {fileID: 7423861191467597400}
m_Layer: 0
m_Name: prefab_audioB
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1740794871874781600
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3749121449083481702}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -1.5441012, y: -1.4355755, z: -5.0895267}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!82 &8364371343008149393
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3749121449083481702}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 8300000, guid: 502e4faa60c5fc441a6a8ae9a61fbf35, type: 3}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 1
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!81 &7423861191467597400
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3749121449083481702}
m_Enabled: 1

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ea7f727cf3cd1b7499c5431e766891c3
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,7 +1,7 @@
{
"name": "com.tuyoogame.yooasset",
"displayName": "YooAsset",
"version": "2.3.10",
"version": "2.3.12",
"unity": "2019.4",
"description": "unity3d resources management system.",
"author": {