Compare commits

...

35 Commits

Author SHA1 Message Date
何冠峰
f0796dccc9 Update GooglePlayFileSystem.cs 2025-07-10 22:50:43 +08:00
何冠峰
f383c59327 update mini game sample
新增Google Play文件系统扩展
2025-07-10 22:43:43 +08:00
何冠峰
e34b9270d2 update mini game
下载器相关代码重构
2025-07-10 10:58:44 +08:00
何冠峰
b90ab01fe9 update file system
下载器相关逻辑代码重构
2025-07-10 10:58:14 +08:00
何冠峰
236468b4a8 update download system
重构下载逻辑代码
2025-07-09 14:52:22 +08:00
何冠峰
6f5fcd55b1 style : 修正拼写错误 2025-07-08 16:42:21 +08:00
何冠峰
4b8f2e3acc update download system
重构下载逻辑代码
2025-07-08 16:41:50 +08:00
何冠峰
090e4f4b15 fix #590 2025-07-01 18:10:17 +08:00
何冠峰
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
121 changed files with 2192 additions and 1017 deletions

View File

@@ -2,6 +2,65 @@
All notable changes to this package will be documented in this file. 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 ## [2.3.10] - 2025-06-17
### Improvements ### Improvements

View File

@@ -67,15 +67,27 @@ namespace YooAsset.Editor
EditorPrefs.SetString(key, buildinFileCopyParams); EditorPrefs.SetString(key, buildinFileCopyParams);
} }
// EncyptionClassName // EncyptionServicesClassName
public static string GetPackageEncyptionClassName(string packageName, string buildPipeline) public static string GetPackageEncyptionServicesClassName(string packageName, string buildPipeline)
{ {
string key = $"{Application.productName}_{packageName}_{buildPipeline}_EncyptionClassName"; string key = $"{Application.productName}_{packageName}_{buildPipeline}_EncyptionServicesClassName";
return EditorPrefs.GetString(key, string.Empty); 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); EditorPrefs.SetString(key, encyptionClassName);
} }

View File

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

View File

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

View File

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

View File

@@ -43,7 +43,8 @@ namespace YooAsset.Editor
buildReport.Summary.EnableSharePackRule = buildParameters.EnableSharePackRule; buildReport.Summary.EnableSharePackRule = buildParameters.EnableSharePackRule;
buildReport.Summary.SingleReferencedPackAlone = buildParameters.SingleReferencedPackAlone; buildReport.Summary.SingleReferencedPackAlone = buildParameters.SingleReferencedPackAlone;
buildReport.Summary.FileNameStyle = buildParameters.FileNameStyle; 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) if (buildParameters is BuiltinBuildParameters)
{ {
var builtinBuildParameters = buildParameters as 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

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 8088863fc7dfbd441bc897380cd7b97f guid: 446513b0ea9f5d445ade0cfb09c5073b
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

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

View File

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

View File

@@ -4,7 +4,7 @@
<ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" /> <ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" />
<ui:Toggle label="Clear Build Cache" name="ClearBuildCache" /> <ui:Toggle label="Clear Build Cache" name="ClearBuildCache" />
<ui:Toggle label="Use Asset Depend DB" name="UseAssetDependency" /> <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="Compression" value="Center" name="Compression" />
<uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" /> <uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" />
<uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" /> <uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" />

View File

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

View File

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

View File

@@ -4,7 +4,7 @@
<ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" /> <ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" />
<ui:Toggle label="Clear Build Cache" name="ClearBuildCache" /> <ui:Toggle label="Clear Build Cache" name="ClearBuildCache" />
<ui:Toggle label="Use Asset Depend DB" name="UseAssetDependency" /> <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="File Name Style" value="Center" name="FileNameStyle" />
<uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" /> <uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" />
<ui:TextField picking-mode="Ignore" label="Copy Buildin File Param" name="CopyBuildinFileParam" /> <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 TemplateContainer Root;
protected TextField _buildOutputField; protected TextField _buildOutputField;
protected TextField _buildVersionField; protected TextField _buildVersionField;
protected PopupField<Type> _encryptionField; protected PopupField<Type> _encryptionServicesField;
protected PopupField<Type> _manifestServicesField;
protected EnumField _compressionField; protected EnumField _compressionField;
protected EnumField _outputNameStyleField; protected EnumField _outputNameStyleField;
protected EnumField _copyBuildinFileOptionField; protected EnumField _copyBuildinFileOptionField;
@@ -44,8 +45,9 @@ namespace YooAsset.Editor
SetBuildVersionField(_buildVersionField); SetBuildVersionField(_buildVersionField);
// 加密方法 // 加密方法
var encryptionContainer = Root.Q("EncryptionContainer"); var popupContainer = Root.Q("PopupContainer");
_encryptionField = CreateEncryptionField(encryptionContainer); _encryptionServicesField = CreateEncryptionServicesField(popupContainer);
_manifestServicesField = CreateManifestServicesField(popupContainer);
// 压缩方式选项 // 压缩方式选项
_compressionField = Root.Q<EnumField>("Compression"); _compressionField = Root.Q<EnumField>("Compression");
@@ -58,6 +60,7 @@ namespace YooAsset.Editor
// 首包文件拷贝参数 // 首包文件拷贝参数
_copyBuildinFileTagsField = Root.Q<TextField>("CopyBuildinFileParam"); _copyBuildinFileTagsField = Root.Q<TextField>("CopyBuildinFileParam");
SetCopyBuildinFileTagsField(_copyBuildinFileTagsField); SetCopyBuildinFileTagsField(_copyBuildinFileTagsField);
SetCopyBuildinFileTagsVisible(_copyBuildinFileTagsField);
// 首包文件拷贝选项 // 首包文件拷贝选项
_copyBuildinFileOptionField = Root.Q<EnumField>("CopyBuildinFileOption"); _copyBuildinFileOptionField = Root.Q<EnumField>("CopyBuildinFileOption");
@@ -118,7 +121,8 @@ namespace YooAsset.Editor
buildParameters.ClearBuildCacheFiles = clearBuildCache; buildParameters.ClearBuildCacheFiles = clearBuildCache;
buildParameters.UseAssetDependencyDB = useAssetDependencyDB; buildParameters.UseAssetDependencyDB = useAssetDependencyDB;
buildParameters.BuiltinShadersBundleName = builtinShaderBundleName; buildParameters.BuiltinShadersBundleName = builtinShaderBundleName;
buildParameters.EncryptionServices = CreateEncryptionInstance(); buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.ManifestServices = CreateManifestServicesInstance();
ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline(); ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true); var buildResult = pipeline.Run(buildParameters, true);

View File

@@ -4,7 +4,7 @@
<ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" /> <ui:TextField picking-mode="Ignore" label="Build Version" name="BuildVersion" />
<ui:Toggle label="Clear Build Cache" name="ClearBuildCache" /> <ui:Toggle label="Clear Build Cache" name="ClearBuildCache" />
<ui:Toggle label="Use Asset Depend DB" name="UseAssetDependency" /> <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="Compression" value="Center" name="Compression" />
<uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" /> <uie:EnumField label="File Name Style" value="Center" name="FileNameStyle" />
<uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" /> <uie:EnumField label="Copy Buildin File Option" value="Center" name="CopyBuildinFileOption" />

View File

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

View File

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

View File

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

View File

@@ -66,7 +66,8 @@ namespace YooAsset.Editor
BindListViewItem("Use Asset Dependency DB", $"{buildReport.Summary.UseAssetDependencyDB}"); BindListViewItem("Use Asset Dependency DB", $"{buildReport.Summary.UseAssetDependencyDB}");
BindListViewItem("Enable Share Pack Rule", $"{buildReport.Summary.EnableSharePackRule}"); BindListViewItem("Enable Share Pack Rule", $"{buildReport.Summary.EnableSharePackRule}");
BindListViewItem("Single Referenced Pack Alone", $"{buildReport.Summary.SingleReferencedPackAlone}"); 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("FileNameStyle", $"{buildReport.Summary.FileNameStyle}");
BindListViewItem("CompressOption", $"{buildReport.Summary.CompressOption}"); BindListViewItem("CompressOption", $"{buildReport.Summary.CompressOption}");
BindListViewItem("DisableWriteTypeTree", $"{buildReport.Summary.DisableWriteTypeTree}"); 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>
/// 设置按钮图标 /// 设置按钮图标
/// </summary> /// </summary>

View File

@@ -0,0 +1,117 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityAssetBundleRequestOperation : UnityWebRequestOperation
{
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
private UnityWebRequestAsyncOperation _requestOperation;
private DownloadHandlerAssetBundle _downloadhandler;
private readonly PackageBundle _packageBundle;
private readonly bool _disableUnityWebCache;
private ESteps _steps = ESteps.None;
/// <summary>
/// 请求结果
/// </summary>
public AssetBundle Result { private set; get; }
internal UnityAssetBundleRequestOperation(PackageBundle packageBundle, bool disableUnityWebCache, string url, int timeout = 60) : base(url, timeout)
{
_packageBundle = packageBundle;
_disableUnityWebCache = disableUnityWebCache;
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
ResetTimeout();
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes;
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
AssetBundle assetBundle = _downloadhandler.assetBundle;
if (assetBundle == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"URL : {_requestURL} Download handler asset bundle object is null !";
}
else
{
_steps = ESteps.Done;
Result = assetBundle;
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
private void CreateWebRequest()
{
_downloadhandler = CreateWebDownloadHandler();
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
_webRequest.downloadHandler = _downloadhandler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
private DownloadHandlerAssetBundle CreateWebDownloadHandler()
{
if (_disableUnityWebCache)
{
var downloadhandler = new DownloadHandlerAssetBundle(_requestURL, _packageBundle.UnityCRC);
#if UNITY_2020_3_OR_NEWER
downloadhandler.autoLoadAssetBundle = false;
#endif
return downloadhandler;
}
else
{
// 注意:优先从浏览器缓存里获取文件
// The file hash defining the version of the asset bundle.
Hash128 fileHash = Hash128.Parse(_packageBundle.FileHash);
var downloadhandler = new DownloadHandlerAssetBundle(_requestURL, fileHash, _packageBundle.UnityCRC);
#if UNITY_2020_3_OR_NEWER
downloadhandler.autoLoadAssetBundle = false;
#endif
return downloadhandler;
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 94254ab8e4496214884c11a891c131c6 guid: e01cc308d7179a34281087fafe455b42
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -5,7 +5,17 @@ namespace YooAsset
{ {
internal class UnityWebDataRequestOperation : UnityWebRequestOperation internal class UnityWebDataRequestOperation : UnityWebRequestOperation
{ {
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
private UnityWebRequestAsyncOperation _requestOperation; private UnityWebRequestAsyncOperation _requestOperation;
private bool _checkTimeout = true;
private ESteps _steps = ESteps.None;
/// <summary> /// <summary>
/// 请求结果 /// 请求结果
@@ -27,27 +37,38 @@ namespace YooAsset
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
_latestDownloadBytes = 0; ResetTimeout();
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest(); CreateWebRequest();
_steps = ESteps.Download; _steps = ESteps.Download;
} }
if (_steps == ESteps.Download) if (_steps == ESteps.Download)
{ {
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes;
Progress = _requestOperation.progress; Progress = _requestOperation.progress;
if (_requestOperation.isDone == false) if (_requestOperation.isDone == false)
{ {
CheckRequestTimeout(); if (_checkTimeout)
CheckRequestTimeout();
return; return;
} }
if (CheckRequestResult()) if (CheckRequestResult())
{ {
_steps = ESteps.Done; var fileData = _webRequest.downloadHandler.data;
Result = _webRequest.downloadHandler.data; if (fileData == null || fileData.Length == 0)
Status = EOperationStatus.Succeed; {
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"URL : {_requestURL} Download handler data is null or empty !";
}
else
{
_steps = ESteps.Done;
Result = fileData;
Status = EOperationStatus.Succeed;
}
} }
else else
{ {
@@ -59,10 +80,13 @@ namespace YooAsset
DisposeRequest(); DisposeRequest();
} }
} }
internal override void InternalAbort()
/// <summary>
/// 不检测超时
/// </summary>
public void DontCheckTimeout()
{ {
_steps = ESteps.Done; _checkTimeout = false;
DisposeRequest();
} }
private void CreateWebRequest() private void CreateWebRequest()

View File

@@ -5,8 +5,18 @@ namespace YooAsset
{ {
internal class UnityWebFileRequestOperation : UnityWebRequestOperation internal class UnityWebFileRequestOperation : UnityWebRequestOperation
{ {
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
private UnityWebRequestAsyncOperation _requestOperation; private UnityWebRequestAsyncOperation _requestOperation;
private readonly string _fileSavePath; private readonly string _fileSavePath;
private ESteps _steps = ESteps.None;
internal UnityWebFileRequestOperation(string url, string fileSavePath, int timeout = 60) : base(url, timeout) internal UnityWebFileRequestOperation(string url, string fileSavePath, int timeout = 60) : base(url, timeout)
{ {
@@ -23,15 +33,15 @@ namespace YooAsset
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
_latestDownloadBytes = 0; ResetTimeout();
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest(); CreateWebRequest();
_steps = ESteps.Download; _steps = ESteps.Download;
} }
if (_steps == ESteps.Download) if (_steps == ESteps.Download)
{ {
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes;
Progress = _requestOperation.progress; Progress = _requestOperation.progress;
if (_requestOperation.isDone == false) if (_requestOperation.isDone == false)
{ {
@@ -54,11 +64,6 @@ namespace YooAsset
DisposeRequest(); DisposeRequest();
} }
} }
internal override void InternalAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest() private void CreateWebRequest()
{ {

View File

@@ -1,6 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Concurrent;
using UnityEngine.Networking; using UnityEngine.Networking;
using UnityEngine; using UnityEngine;
@@ -8,24 +6,33 @@ namespace YooAsset
{ {
internal abstract class UnityWebRequestOperation : AsyncOperationBase internal abstract class UnityWebRequestOperation : AsyncOperationBase
{ {
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
protected UnityWebRequest _webRequest; protected UnityWebRequest _webRequest;
protected readonly string _requestURL; protected readonly string _requestURL;
protected ESteps _steps = ESteps.None;
// 超时相关 // 超时相关
protected readonly float _timeout; private readonly float _timeout;
protected ulong _latestDownloadBytes; private ulong _latestDownloadBytes;
protected float _latestDownloadRealtime; private float _latestDownloadRealtime;
private bool _isAbort = false; private bool _isAbort = false;
/// <summary>
/// HTTP返回码
/// </summary>
public long HttpCode { private set; get; }
/// <summary>
/// 当前下载的字节数
/// </summary>
public long DownloadedBytes { protected set; get; }
/// <summary>
/// 当前下载进度0f - 1f
/// </summary>
public float DownloadProgress { protected set; get; }
/// <summary>
/// 请求的URL地址
/// </summary>
public string URL public string URL
{ {
get { return _requestURL; } get { return _requestURL; }
@@ -36,6 +43,20 @@ namespace YooAsset
_requestURL = url; _requestURL = url;
_timeout = timeout; _timeout = timeout;
} }
internal override void InternalAbort()
{
//TODO
// 1. 编辑器下停止运行游戏的时候主动终止下载任务
// 2. 真机上销毁包裹的时候主动终止下载任务
if (_isAbort == false)
{
if (_webRequest != null)
{
_webRequest.Abort();
_isAbort = true;
}
}
}
/// <summary> /// <summary>
/// 释放下载器 /// 释放下载器
@@ -44,20 +65,33 @@ namespace YooAsset
{ {
if (_webRequest != null) if (_webRequest != null)
{ {
//注意引擎底层会自动调用Abort方法
_webRequest.Dispose(); _webRequest.Dispose();
_webRequest = null; _webRequest = null;
} }
} }
/// <summary>
/// 重置超时计时
/// </summary>
protected void ResetTimeout()
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
/// <summary> /// <summary>
/// 检测超时 /// 检测超时
/// </summary> /// </summary>
protected void CheckRequestTimeout() protected void CheckRequestTimeout()
{ {
if (_webRequest.isDone)
return;
// 注意:在连续时间段内无新增下载数据及判定为超时 // 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false) if (_isAbort == false)
{ {
if ( _latestDownloadBytes != _webRequest.downloadedBytes) if (_latestDownloadBytes != _webRequest.downloadedBytes)
{ {
_latestDownloadBytes = _webRequest.downloadedBytes; _latestDownloadBytes = _webRequest.downloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup; _latestDownloadRealtime = Time.realtimeSinceStartup;
@@ -66,6 +100,7 @@ namespace YooAsset
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime; float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout) if (offset > _timeout)
{ {
YooLogger.Warning($"Web request timeout : {_requestURL}");
_webRequest.Abort(); _webRequest.Abort();
_isAbort = true; _isAbort = true;
} }
@@ -77,6 +112,8 @@ namespace YooAsset
/// </summary> /// </summary>
protected bool CheckRequestResult() protected bool CheckRequestResult()
{ {
HttpCode = _webRequest.responseCode;
#if UNITY_2020_3_OR_NEWER #if UNITY_2020_3_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success) if (_webRequest.result != UnityWebRequest.Result.Success)
{ {

View File

@@ -5,7 +5,16 @@ namespace YooAsset
{ {
internal class UnityWebTextRequestOperation : UnityWebRequestOperation internal class UnityWebTextRequestOperation : UnityWebRequestOperation
{ {
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
private UnityWebRequestAsyncOperation _requestOperation; private UnityWebRequestAsyncOperation _requestOperation;
private ESteps _steps = ESteps.None;
/// <summary> /// <summary>
/// 请求结果 /// 请求结果
@@ -27,15 +36,15 @@ namespace YooAsset
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
_latestDownloadBytes = 0; ResetTimeout();
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest(); CreateWebRequest();
_steps = ESteps.Download; _steps = ESteps.Download;
} }
if (_steps == ESteps.Download) if (_steps == ESteps.Download)
{ {
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes;
Progress = _requestOperation.progress; Progress = _requestOperation.progress;
if (_requestOperation.isDone == false) if (_requestOperation.isDone == false)
{ {
@@ -45,9 +54,19 @@ namespace YooAsset
if (CheckRequestResult()) if (CheckRequestResult())
{ {
_steps = ESteps.Done; var fileText = _webRequest.downloadHandler.text;
Result = _webRequest.downloadHandler.text; if (string.IsNullOrEmpty(fileText))
Status = EOperationStatus.Succeed; {
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"URL : {_requestURL} Download handler text is null or empty !";
}
else
{
_steps = ESteps.Done;
Result = fileText;
Status = EOperationStatus.Succeed;
}
} }
else else
{ {
@@ -59,11 +78,6 @@ namespace YooAsset
DisposeRequest(); DisposeRequest();
} }
} }
internal override void InternalAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest() private void CreateWebRequest()
{ {

View File

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

View File

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

View File

@@ -88,6 +88,16 @@ namespace YooAsset
/// 自定义参数:解密方法类 /// 自定义参数:解密方法类
/// </summary> /// </summary>
public IDecryptionServices DecryptionServices { private set; get; } public IDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件服务类
/// </summary>
public ICopyLocalFileServices CopyLocalFileServices { private set; get; }
#endregion #endregion
@@ -115,7 +125,7 @@ namespace YooAsset
} }
public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options) public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options)
{ {
// 注意:业务层的解压下载器会依赖内置文件系统的下载方法 // 注意:业务层的解压器会依赖方法
options.ImportFilePath = GetBuildinFileLoadPath(bundle); options.ImportFilePath = GetBuildinFileLoadPath(bundle);
return _unpackFileSystem.DownloadFileAsync(bundle, options); return _unpackFileSystem.DownloadFileAsync(bundle, options);
} }
@@ -174,6 +184,14 @@ namespace YooAsset
{ {
DecryptionServices = (IDecryptionServices)value; DecryptionServices = (IDecryptionServices)value;
} }
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else if (name == FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES)
{
CopyLocalFileServices = (ICopyLocalFileServices)value;
}
else else
{ {
YooLogger.Warning($"Invalid parameter : {name}"); YooLogger.Warning($"Invalid parameter : {name}");
@@ -196,6 +214,7 @@ namespace YooAsset
_unpackFileSystem.SetParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, InstallClearMode); _unpackFileSystem.SetParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, InstallClearMode);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension); _unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, DecryptionServices); _unpackFileSystem.SetParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, DecryptionServices);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES, CopyLocalFileServices);
_unpackFileSystem.OnCreate(packageName, null); _unpackFileSystem.OnCreate(packageName, null);
} }
public virtual void OnDestroy() public virtual void OnDestroy()

View File

@@ -11,7 +11,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 在构建应用程序前自动生成内置资源目录文件。 /// 在构建应用程序前自动生成内置资源目录文件。
/// 原理搜索StreamingAssets目录下的所有资源文件然后将这些文件信息写入文件,并存储在Resources目录下 /// 原理搜索StreamingAssets目录下的所有资源文件将这些文件信息写入文件然后在运行时做查询用途
/// </summary> /// </summary>
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{ {
@@ -21,7 +21,7 @@ namespace YooAsset
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath); DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists == false) if (rootDirectory.Exists == false)
{ {
UnityEngine.Debug.LogWarning($"Can not found StreamingAssets root directory : {rootPath}"); Debug.LogWarning($"Can not found StreamingAssets root directory : {rootPath}");
return; return;
} }
@@ -31,10 +31,17 @@ namespace YooAsset
{ {
string packageName = subDirectory.Name; string packageName = subDirectory.Name;
string pacakgeDirectory = subDirectory.FullName; string pacakgeDirectory = subDirectory.FullName;
bool result = CreateBuildinCatalogFile(packageName, pacakgeDirectory); try
if (result == false)
{ {
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,13 +49,13 @@ namespace YooAsset
/// <summary> /// <summary>
/// 生成包裹的内置资源目录文件 /// 生成包裹的内置资源目录文件
/// </summary> /// </summary>
public static bool CreateBuildinCatalogFile(string packageName, string pacakgeDirectory) public static bool CreateBuildinCatalogFile(IManifestServices services, string packageName, string packageDirectory)
{ {
// 获取资源清单版本 // 获取资源清单版本
string packageVersion; string packageVersion;
{ {
string versionFileName = YooAssetSettingsData.GetPackageVersionFileName(packageName); string versionFileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
string versionFilePath = $"{pacakgeDirectory}/{versionFileName}"; string versionFilePath = $"{packageDirectory}/{versionFileName}";
if (File.Exists(versionFilePath) == false) if (File.Exists(versionFilePath) == false)
{ {
Debug.LogError($"Can not found package version file : {versionFilePath}"); Debug.LogError($"Can not found package version file : {versionFilePath}");
@@ -62,7 +69,7 @@ namespace YooAsset
PackageManifest packageManifest; PackageManifest packageManifest;
{ {
string manifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion); string manifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
string manifestFilePath = $"{pacakgeDirectory}/{manifestFileName}"; string manifestFilePath = $"{packageDirectory}/{manifestFileName}";
if (File.Exists(manifestFilePath) == false) if (File.Exists(manifestFilePath) == false)
{ {
Debug.LogError($"Can not found package manifest file : {manifestFilePath}"); Debug.LogError($"Can not found package manifest file : {manifestFilePath}");
@@ -70,7 +77,7 @@ namespace YooAsset
} }
var binaryData = FileUtility.ReadAllBytes(manifestFilePath); var binaryData = FileUtility.ReadAllBytes(manifestFilePath);
packageManifest = ManifestTools.DeserializeFromBinary(binaryData); packageManifest = ManifestTools.DeserializeFromBinary(binaryData, services);
} }
// 获取文件名映射关系 // 获取文件名映射关系
@@ -103,7 +110,7 @@ namespace YooAsset
}; };
// 记录所有内置资源文件 // 记录所有内置资源文件
DirectoryInfo rootDirectory = new DirectoryInfo(pacakgeDirectory); DirectoryInfo rootDirectory = new DirectoryInfo(packageDirectory);
FileInfo[] fileInfos = rootDirectory.GetFiles(); FileInfo[] fileInfos = rootDirectory.GetFiles();
foreach (var fileInfo in fileInfos) foreach (var fileInfo in fileInfos)
{ {
@@ -128,13 +135,13 @@ namespace YooAsset
} }
// 创建输出文件 // 创建输出文件
string jsonFilePath = $"{pacakgeDirectory}/{DefaultBuildinFileSystemDefine.BuildinCatalogJsonFileName}"; string jsonFilePath = $"{packageDirectory}/{DefaultBuildinFileSystemDefine.BuildinCatalogJsonFileName}";
if (File.Exists(jsonFilePath)) if (File.Exists(jsonFilePath))
File.Delete(jsonFilePath); File.Delete(jsonFilePath);
CatalogTools.SerializeToJson(jsonFilePath, buildinFileCatalog); CatalogTools.SerializeToJson(jsonFilePath, buildinFileCatalog);
// 创建输出文件 // 创建输出文件
string binaryFilePath = $"{pacakgeDirectory}/{DefaultBuildinFileSystemDefine.BuildinCatalogBinaryFileName}"; string binaryFilePath = $"{packageDirectory}/{DefaultBuildinFileSystemDefine.BuildinCatalogBinaryFileName}";
if (File.Exists(binaryFilePath)) if (File.Exists(binaryFilePath))
File.Delete(binaryFilePath); File.Delete(binaryFilePath);
CatalogTools.SerializeToBinary(binaryFilePath, buildinFileCatalog); CatalogTools.SerializeToBinary(binaryFilePath, buildinFileCatalog);

View File

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

View File

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

View File

@@ -58,7 +58,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 自定义参数:远程服务接口 /// 自定义参数:远程服务接口
/// </summary> /// </summary>
public IRemoteServices RemoteServices { private set; get; } = null; public IRemoteServices RemoteServices { private set; get; }
/// <summary> /// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别 /// 自定义参数:初始化的时候缓存文件校验级别
@@ -99,6 +99,16 @@ namespace YooAsset
/// 自定义参数:解密方法类 /// 自定义参数:解密方法类
/// </summary> /// </summary>
public IDecryptionServices DecryptionServices { private set; get; } public IDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestServices ManifestServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件服务类
/// </summary>
public ICopyLocalFileServices CopyLocalFileServices { private set; get; }
#endregion #endregion
@@ -156,12 +166,23 @@ namespace YooAsset
} }
public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options) public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options)
{ {
var downloader = DownloadCenter.DownloadFileAsync(bundle, options); // 获取下载地址
downloader.Reference(); //增加下载器的引用计数 if (string.IsNullOrEmpty(options.ImportFilePath))
{
// 注意:如果是解压文件系统类,这里会返回本地内置文件的下载路径
string mainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);
string fallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);
options.SetURL(mainURL, fallbackURL);
}
else
{
// 注意:把本地导入文件路径转换为下载器请求地址
string mainURL = DownloadSystemHelper.ConvertToWWWPath(options.ImportFilePath);
options.SetURL(mainURL, mainURL);
}
// 注意:将下载器进行包裹,可以避免父类任务终止的时候,连带子任务里的下载器也一起被终止! var downloader = new DownloadPackageBundleOperation(this, bundle, options);
var wrapper = new DownloadFileWrapper(downloader); return downloader;
return wrapper;
} }
public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle) public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
{ {
@@ -221,6 +242,14 @@ namespace YooAsset
{ {
DecryptionServices = (IDecryptionServices)value; DecryptionServices = (IDecryptionServices)value;
} }
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestServices)value;
}
else if (name == FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES)
{
CopyLocalFileServices = (ICopyLocalFileServices)value;
}
else else
{ {
YooLogger.Warning($"Invalid parameter : {name}"); YooLogger.Warning($"Invalid parameter : {name}");

View File

@@ -55,7 +55,6 @@ namespace YooAsset
if (_steps == ESteps.DownloadFile) if (_steps == ESteps.DownloadFile)
{ {
// 注意边玩边下下载器引用计数没有Release
if (_downloadFileOp == null) if (_downloadFileOp == null)
{ {
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60); DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60);
@@ -228,9 +227,6 @@ namespace YooAsset
{ {
if (ExecuteWhileDone()) if (ExecuteWhileDone())
{ {
if (_downloadFileOp != null && _downloadFileOp.Status == EOperationStatus.Failed)
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote !");
_steps = ESteps.Done; _steps = ESteps.Done;
break; break;
} }
@@ -306,7 +302,6 @@ namespace YooAsset
if (_steps == ESteps.DownloadFile) if (_steps == ESteps.DownloadFile)
{ {
// 注意边玩边下下载器引用计数没有Release
if (_downloadFileOp == null) if (_downloadFileOp == null)
{ {
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60); DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60);
@@ -360,10 +355,6 @@ namespace YooAsset
{ {
if (ExecuteWhileDone()) if (ExecuteWhileDone())
{ {
//TODO 拷贝本地文件失败也会触发该错误!
if (_downloadFileOp != null && _downloadFileOp.Status == EOperationStatus.Failed)
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote !");
_steps = ESteps.Done; _steps = ESteps.Done;
break; break;
} }

View File

@@ -3,10 +3,21 @@ using System.Collections.Generic;
namespace YooAsset namespace YooAsset
{ {
/// <summary>
/// 下载器单元测试
/// 1. 下载失败重试机制
/// 2. 下载引用计数机制
/// 3. 最大下载并发机制
/// 4. 异步下载远端资源
/// 5. 同步下载远端资源
/// 6. 异步拷贝本地资源
/// 7. 同步拷贝本地资源
/// 9. 断点续传下载器
/// </summary>
internal class DownloadCenterOperation : AsyncOperationBase internal class DownloadCenterOperation : AsyncOperationBase
{ {
private readonly DefaultCacheFileSystem _fileSystem; private readonly DefaultCacheFileSystem _fileSystem;
protected readonly Dictionary<string, DefaultDownloadFileOperation> _downloaders = new Dictionary<string, DefaultDownloadFileOperation>(1000); protected readonly Dictionary<string, UnityDownloadFileOperation> _downloaders = new Dictionary<string, UnityDownloadFileOperation>(1000);
protected readonly List<string> _removeDownloadList = new List<string>(1000); protected readonly List<string> _removeDownloadList = new List<string>(1000);
public DownloadCenterOperation(DefaultCacheFileSystem fileSystem) public DownloadCenterOperation(DefaultCacheFileSystem fileSystem)
@@ -74,41 +85,41 @@ namespace YooAsset
/// <summary> /// <summary>
/// 创建下载任务 /// 创建下载任务
/// </summary> /// </summary>
public FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options) public UnityDownloadFileOperation DownloadFileAsync(PackageBundle bundle, string url, int timeout)
{ {
// 查询旧的下载器 // 查询旧的下载器
if (_downloaders.TryGetValue(bundle.BundleGUID, out var oldDownloader)) if (_downloaders.TryGetValue(bundle.BundleGUID, out var oldDownloader))
{ {
oldDownloader.Reference();
return oldDownloader; return oldDownloader;
} }
// 设置请求URL // 创建新的下载器
if (string.IsNullOrEmpty(options.ImportFilePath)) UnityDownloadFileOperation newDownloader;
bool isRequestLocalFile = DownloadSystemHelper.IsRequestLocalFile(url);
if (isRequestLocalFile)
{ {
options.MainURL = _fileSystem.RemoteServices.GetRemoteMainURL(bundle.FileName); newDownloader = new UnityDownloadLocalFileOperation(_fileSystem, bundle, url, timeout);
options.FallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(bundle.FileName); AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
} }
else else
{ {
// 注意:把本地文件路径指定为远端下载地址 if (bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize)
options.MainURL = DownloadSystemHelper.ConvertToWWWPath(options.ImportFilePath); {
options.FallbackURL = options.MainURL; newDownloader = new UnityDownloadResumeFileOperation(_fileSystem, bundle, url, timeout);
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
}
else
{
newDownloader = new UnityDownloadNormalFileOperation(_fileSystem, bundle, url, timeout);
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
}
} }
// 创建新的下载器 newDownloader.Reference();
DefaultDownloadFileOperation 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; return newDownloader;
} }

View File

@@ -1,87 +0,0 @@
using System;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 支持Unity2018版本的断点续传下载器
/// </summary>
internal class DownloadHandlerFileRange : DownloadHandlerScript
{
private string _fileSavePath;
private long _fileTotalSize;
private UnityWebRequest _webRequest;
private FileStream _fileStream;
private long _localFileSize = 0;
private long _curFileSize = 0;
public DownloadHandlerFileRange(string fileSavePath, long fileTotalSize, UnityWebRequest webRequest) : base(new byte[1024 * 1024])
{
_fileSavePath = fileSavePath;
_fileTotalSize = fileTotalSize;
_webRequest = webRequest;
if (File.Exists(fileSavePath))
{
FileInfo fileInfo = new FileInfo(fileSavePath);
_localFileSize = fileInfo.Length;
}
_fileStream = new FileStream(_fileSavePath, FileMode.Append, FileAccess.Write);
_curFileSize = _localFileSize;
}
protected override bool ReceiveData(byte[] data, int dataLength)
{
if (data == null || dataLength == 0 || _webRequest.responseCode >= 400)
return false;
if (_fileStream == null)
return false;
_fileStream.Write(data, 0, dataLength);
_curFileSize += dataLength;
return true;
}
/// <summary>
/// UnityWebRequest.downloadHandler.data
/// </summary>
protected override byte[] GetData()
{
return null;
}
/// <summary>
/// UnityWebRequest.downloadHandler.text
/// </summary>
protected override string GetText()
{
return null;
}
/// <summary>
/// UnityWebRequest.downloadProgress
/// </summary>
protected override float GetProgress()
{
return _fileTotalSize == 0 ? 0 : ((float)_curFileSize) / _fileTotalSize;
}
/// <summary>
/// 释放下载句柄
/// </summary>
public void Cleanup()
{
if (_fileStream != null)
{
_fileStream.Flush();
_fileStream.Dispose();
_fileStream = null;
}
}
}
}

View File

@@ -0,0 +1,164 @@
using UnityEngine;
namespace YooAsset
{
internal class DownloadPackageBundleOperation : FSDownloadFileOperation
{
protected enum ESteps
{
None,
CheckExists,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
// 下载参数
protected readonly DefaultCacheFileSystem _fileSystem;
protected readonly DownloadFileOptions _options;
private UnityDownloadFileOperation _unityDownloadFileOp;
protected int _requestCount = 0;
protected float _tryAgainTimer;
protected int _failedTryAgain;
private ESteps _steps = ESteps.None;
internal DownloadPackageBundleOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle)
{
_fileSystem = fileSystem;
_options = options;
_failedTryAgain = options.FailedTryAgain;
}
internal override void InternalStart()
{
_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
{
_steps = ESteps.CreateRequest;
}
}
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
if (_options.IsValid() == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Download file options is invalid !";
Debug.Log(Error);
return;
}
string url = GetRequestURL();
_unityDownloadFileOp = _fileSystem.DownloadCenter.DownloadFileAsync(Bundle, url, _options.Timeout);
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
if (IsWaitForAsyncComplete)
_unityDownloadFileOp.WaitForAsyncComplete();
// 因为并发数量限制,下载器可能被挂起!
if (_unityDownloadFileOp.Status == EOperationStatus.None)
return;
_unityDownloadFileOp.UpdateOperation();
Progress = _unityDownloadFileOp.Progress;
DownloadedBytes = _unityDownloadFileOp.DownloadedBytes;
DownloadProgress = _unityDownloadFileOp.DownloadProgress;
if (_unityDownloadFileOp.IsDone == false)
return;
if (_unityDownloadFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
if (IsWaitForAsyncComplete == false && _failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_unityDownloadFileOp.URL} Try again !");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _unityDownloadFileOp.Error;
YooLogger.Error(Error);
}
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
internal override void InternalAbort()
{
// 注意:取消下载任务的时候引用计数减一
if (_steps != ESteps.Done)
{
if (_unityDownloadFileOp != null)
{
_unityDownloadFileOp.Release();
}
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

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

View File

@@ -0,0 +1,52 @@

namespace YooAsset
{
internal abstract class UnityDownloadFileOperation : UnityWebRequestOperation
{
protected enum ESteps
{
None,
CreateRequest,
Download,
CopyLocalFile,
VerifyFile,
Done,
}
protected readonly DefaultCacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected readonly string _tempFilePath;
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
internal UnityDownloadFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url, int timeout) : base(url, timeout)
{
_fileSystem = fileSystem;
_bundle = bundle;
_tempFilePath = _fileSystem.GetTempFilePath(bundle);
}
internal override string InternalGetDesc()
{
return $"RefCount : {RefCount}";
}
/// <summary>
/// 减少引用计数
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 增加引用计数
/// </summary>
public void Reference()
{
RefCount++;
}
}
}

View File

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

View File

@@ -4,66 +4,41 @@ using UnityEngine.Networking;
namespace YooAsset namespace YooAsset
{ {
internal sealed class DownloadNormalFileOperation : DefaultDownloadFileOperation internal class UnityDownloadLocalFileOperation : UnityDownloadFileOperation
{ {
private readonly DefaultCacheFileSystem _fileSystem;
private VerifyTempFileOperation _verifyOperation; private VerifyTempFileOperation _verifyOperation;
private bool _isReuqestLocalFile;
private string _tempFilePath;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
internal DownloadNormalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle, options) internal UnityDownloadLocalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url, int timeout = 60)
: base(fileSystem, bundle, url, timeout)
{ {
_fileSystem = fileSystem;
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_isReuqestLocalFile = DownloadSystemHelper.IsRequestLocalFile(Options.MainURL); if (_fileSystem.CopyLocalFileServices != null)
_tempFilePath = _fileSystem.GetTempFilePath(Bundle); _steps = ESteps.CopyLocalFile;
_steps = ESteps.CheckExists; else
_steps = ESteps.CreateRequest;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
// 检测文件是否存在
if (_steps == ESteps.CheckExists)
{
if (_fileSystem.Exists(Bundle))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.CreateRequest;
}
}
// 创建下载器 // 创建下载器
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
FileUtility.CreateFileDirectory(_tempFilePath); FileUtility.CreateFileDirectory(_tempFilePath);
// 删除临时文件
if (File.Exists(_tempFilePath)) if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
// 获取请求地址 ResetTimeout();
_requestURL = GetRequestURL();
// 重置请求
ResetRequestFiled();
// 创建下载器
CreateWebRequest(); CreateWebRequest();
_steps = ESteps.Download;
_steps = ESteps.CheckRequest;
} }
// 检测下载结果 // 检测下载结果
if (_steps == ESteps.CheckRequest) if (_steps == ESteps.Download)
{ {
DownloadProgress = _webRequest.downloadProgress; DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes; DownloadedBytes = (long)_webRequest.downloadedBytes;
@@ -76,27 +51,67 @@ namespace YooAsset
// 检查网络错误 // 检查网络错误
if (CheckRequestResult()) if (CheckRequestResult())
_steps = ESteps.VerifyTempFile; {
_steps = ESteps.VerifyFile;
}
else else
_steps = ESteps.TryAgain; {
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器 // 注意:最终释放请求器
DisposeWebRequest(); DisposeRequest();
}
// 拷贝内置文件
if (_steps == ESteps.CopyLocalFile)
{
FileUtility.CreateFileDirectory(_tempFilePath);
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
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.VerifyFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {_requestURL}";
}
}
catch (System.Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {ex.Message}";
}
} }
// 验证下载文件 // 验证下载文件
if (_steps == ESteps.VerifyTempFile) if (_steps == ESteps.VerifyFile)
{ {
var element = new TempFileElement(_tempFilePath, Bundle.FileCRC, Bundle.FileSize); if (_verifyOperation == null)
_verifyOperation = new VerifyTempFileOperation(element); {
_verifyOperation.StartOperation(); var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize);
AddChildOperation(_verifyOperation); _verifyOperation = new VerifyTempFileOperation(element);
_steps = ESteps.CheckVerifyTempFile; _verifyOperation.StartOperation();
} AddChildOperation(_verifyOperation);
}
// 等待验证完成
if (_steps == ESteps.CheckVerifyTempFile)
{
if (IsWaitForAsyncComplete) if (IsWaitForAsyncComplete)
_verifyOperation.WaitForAsyncComplete(); _verifyOperation.WaitForAsyncComplete();
@@ -106,7 +121,7 @@ namespace YooAsset
if (_verifyOperation.Status == EOperationStatus.Succeed) if (_verifyOperation.Status == EOperationStatus.Succeed)
{ {
if (_fileSystem.WriteCacheBundleFile(Bundle, _tempFilePath)) if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath))
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
@@ -116,12 +131,12 @@ namespace YooAsset
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = $"{_fileSystem.GetType().FullName} failed to write file !"; Error = $"{_fileSystem.GetType().FullName} failed to write file !";
YooLogger.Error(Error);
} }
} }
else else
{ {
_steps = ESteps.TryAgain; _steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _verifyOperation.Error; Error = _verifyOperation.Error;
} }
@@ -129,60 +144,18 @@ namespace YooAsset
if (File.Exists(_tempFilePath)) if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
} }
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
//TODO 拷贝本地文件失败后不再尝试!
if (_isReuqestLocalFile)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
if (FailedTryAgain <= 0)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
FailedTryAgain--;
_steps = ESteps.CreateRequest;
YooLogger.Warning(Error);
}
}
}
internal override void InternalAbort()
{
_steps = ESteps.Done;
DisposeWebRequest();
} }
internal override void InternalWaitForAsyncComplete() internal override void InternalWaitForAsyncComplete()
{ {
while (true) while (true)
{ {
//TODO 如果是导入或解压本地文件,执行等待完毕 //TODO 等待导入或解压本地文件完毕,该操作会挂起主线程!
if (_isReuqestLocalFile) InternalUpdate();
{ if (IsDone)
InternalUpdate(); break;
if (IsDone)
break; // 短暂休眠避免完全卡死
} System.Threading.Thread.Sleep(1);
else
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
} }
} }
@@ -195,14 +168,5 @@ namespace YooAsset
_webRequest.disposeDownloadHandlerOnDispose = true; _webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest(); _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

@@ -0,0 +1,126 @@
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal sealed class UnityDownloadNormalFileOperation : UnityDownloadFileOperation
{
private VerifyTempFileOperation _verifyOperation;
private ESteps _steps = ESteps.None;
internal UnityDownloadNormalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url, int timeout = 60)
: base(fileSystem, bundle, url, timeout)
{
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
FileUtility.CreateFileDirectory(_tempFilePath);
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
ResetTimeout();
CreateWebRequest();
_steps = ESteps.Download;
}
// 检测下载结果
if (_steps == ESteps.Download)
{
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = (long)_webRequest.downloadedBytes;
Progress = DownloadProgress;
if (_webRequest.isDone == false)
{
CheckRequestTimeout();
return;
}
// 检查网络错误
if (CheckRequestResult())
{
_steps = ESteps.VerifyFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
// 验证下载文件
if (_steps == ESteps.VerifyFile)
{
if (_verifyOperation == null)
{
var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize);
_verifyOperation = new VerifyTempFileOperation(element);
_verifyOperation.StartOperation();
AddChildOperation(_verifyOperation);
}
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 ! {_tempFilePath}";
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _verifyOperation.Error;
}
// 注意:验证完成后直接删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
internal override void InternalWaitForAsyncComplete()
{
if (_steps != ESteps.Done)
{
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {_requestURL} !");
}
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
}
}
}

View File

@@ -4,66 +4,38 @@ using UnityEngine.Networking;
namespace YooAsset namespace YooAsset
{ {
internal sealed class DownloadResumeFileOperation : DefaultDownloadFileOperation internal sealed class UnityDownloadResumeFileOperation : UnityDownloadFileOperation
{ {
private readonly DefaultCacheFileSystem _fileSystem;
private DownloadHandlerFileRange _downloadHandle;
private VerifyTempFileOperation _verifyOperation; private VerifyTempFileOperation _verifyOperation;
private bool _isReuqestLocalFile;
private long _fileOriginLength = 0; private long _fileOriginLength = 0;
private string _tempFilePath;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
internal UnityDownloadResumeFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string url, int timeout = 60)
internal DownloadResumeFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle, options) : base(fileSystem, bundle, url, timeout)
{ {
_fileSystem = fileSystem;
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_isReuqestLocalFile = DownloadSystemHelper.IsRequestLocalFile(Options.MainURL); _steps = ESteps.CreateRequest;
_tempFilePath = _fileSystem.GetTempFilePath(Bundle);
_steps = ESteps.CheckExists;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
// 检测文件是否存在
if (_steps == ESteps.CheckExists)
{
if (_fileSystem.Exists(Bundle))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.CreateRequest;
}
}
// 创建下载器 // 创建下载器
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
FileUtility.CreateFileDirectory(_tempFilePath); FileUtility.CreateFileDirectory(_tempFilePath);
// 获取请求地址
_requestURL = GetRequestURL();
// 重置变量
ResetRequestFiled();
// 获取下载起始位置 // 获取下载起始位置
_fileOriginLength = 0; _fileOriginLength = 0;
long fileBeginLength = -1; long fileBeginLength = -1;
if (File.Exists(_tempFilePath)) if (File.Exists(_tempFilePath))
{ {
FileInfo fileInfo = new FileInfo(_tempFilePath); FileInfo fileInfo = new FileInfo(_tempFilePath);
if (fileInfo.Length >= Bundle.FileSize) if (fileInfo.Length >= _bundle.FileSize)
{ {
// 删除临时文件
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
} }
else else
@@ -74,17 +46,17 @@ namespace YooAsset
} }
} }
// 创建下载器 ResetTimeout();
CreateWebRequest(fileBeginLength); CreateWebRequest(fileBeginLength);
_steps = ESteps.Download;
_steps = ESteps.CheckRequest;
} }
// 检测下载结果 // 检测下载结果
if (_steps == ESteps.CheckRequest) if (_steps == ESteps.Download)
{ {
DownloadProgress = _webRequest.downloadProgress; DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _fileOriginLength + (long)_webRequest.downloadedBytes; DownloadedBytes = _fileOriginLength + (long)_webRequest.downloadedBytes;
Progress = DownloadProgress;
if (_webRequest.isDone == false) if (_webRequest.isDone == false)
{ {
CheckRequestTimeout(); CheckRequestTimeout();
@@ -93,30 +65,33 @@ namespace YooAsset
// 检查网络错误 // 检查网络错误
if (CheckRequestResult()) if (CheckRequestResult())
_steps = ESteps.VerifyTempFile; {
_steps = ESteps.VerifyFile;
}
else else
_steps = ESteps.TryAgain; {
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 在遇到特殊错误的时候删除文件 // 在遇到特殊错误的时候删除文件
ClearTempFileWhenError(); ClearTempFileWhenError();
// 注意:最终释放请求器 // 注意:最终释放请求器
DisposeWebRequest(); DisposeRequest();
} }
// 验证下载文件 // 验证下载文件
if (_steps == ESteps.VerifyTempFile) if (_steps == ESteps.VerifyFile)
{ {
var element = new TempFileElement(_tempFilePath, Bundle.FileCRC, Bundle.FileSize); if (_verifyOperation == null)
_verifyOperation = new VerifyTempFileOperation(element); {
_verifyOperation.StartOperation(); var element = new TempFileElement(_tempFilePath, _bundle.FileCRC, _bundle.FileSize);
AddChildOperation(_verifyOperation); _verifyOperation = new VerifyTempFileOperation(element);
_steps = ESteps.CheckVerifyTempFile; _verifyOperation.StartOperation();
} AddChildOperation(_verifyOperation);
}
// 等待验证完成
if (_steps == ESteps.CheckVerifyTempFile)
{
if (IsWaitForAsyncComplete) if (IsWaitForAsyncComplete)
_verifyOperation.WaitForAsyncComplete(); _verifyOperation.WaitForAsyncComplete();
@@ -126,116 +101,38 @@ namespace YooAsset
if (_verifyOperation.Status == EOperationStatus.Succeed) if (_verifyOperation.Status == EOperationStatus.Succeed)
{ {
if (_fileSystem.WriteCacheBundleFile(Bundle, _tempFilePath)) if (_fileSystem.WriteCacheBundleFile(_bundle, _tempFilePath))
{ {
Status = EOperationStatus.Succeed;
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed;
} }
else else
{ {
Error = $"{_fileSystem.GetType().FullName} failed to write file !";
Status = EOperationStatus.Failed;
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{_fileSystem.GetType().FullName} failed to write file !";
} }
} }
else else
{ {
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _verifyOperation.Error; Error = _verifyOperation.Error;
_steps = ESteps.TryAgain;
} }
// 注意:验证完成后直接删除文件 // 注意:验证完成后直接删除文件
if (File.Exists(_tempFilePath)) if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
} }
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
//TODO 拷贝本地文件失败后不再尝试!
if (_isReuqestLocalFile)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
if (FailedTryAgain <= 0)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
FailedTryAgain--;
_steps = ESteps.CreateRequest;
YooLogger.Warning(Error);
}
}
}
internal override void InternalAbort()
{
_steps = ESteps.Done;
DisposeWebRequest();
} }
internal override void InternalWaitForAsyncComplete() internal override void InternalWaitForAsyncComplete()
{ {
while (true) if (_steps != ESteps.Done)
{ {
//TODO 如果是导入或解压本地文件,执行等待完毕 YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {_requestURL} !");
if (_isReuqestLocalFile)
{
InternalUpdate();
if (IsDone)
break;
}
else
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
} }
} }
private void CreateWebRequest(long beginLength)
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
#if UNITY_2019_4_OR_NEWER
var handler = new DownloadHandlerFile(_tempFilePath, true);
handler.removeFileOnAbort = false;
#else
var handler = new DownloadHandlerFileRange(FileSavePath, Bundle.FileSize, _webRequest);
_downloadHandle = handler;
#endif
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
if (beginLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={beginLength}-");
_webRequest.SendWebRequest();
}
private void DisposeWebRequest()
{
if (_downloadHandle != null)
{
_downloadHandle.Cleanup();
_downloadHandle = null;
}
if (_webRequest != null)
{
//注意引擎底层会自动调用Abort方法
_webRequest.Dispose();
_webRequest = null;
}
}
private void ClearTempFileWhenError() private void ClearTempFileWhenError()
{ {
if (_fileSystem.ResumeDownloadResponseCodes == null) if (_fileSystem.ResumeDownloadResponseCodes == null)
@@ -248,5 +145,16 @@ namespace YooAsset
File.Delete(_tempFilePath); File.Delete(_tempFilePath);
} }
} }
private void CreateWebRequest(long fileBeginLength)
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
var handler = new DownloadHandlerFile(_tempFilePath, true);
handler.removeFileOnAbort = false;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
if (fileBeginLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={fileBeginLength}-");
_webRequest.SendWebRequest();
}
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -34,19 +34,20 @@ namespace YooAsset
{ {
if (_downloadAssetBundleOp == null) if (_downloadAssetBundleOp == null)
{ {
string mainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName);
string fallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName);
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60); DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60);
options.MainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName); options.SetURL(mainURL, fallbackURL);
options.FallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName);
if (_bundle.Encrypted) if (_bundle.Encrypted)
{ {
_downloadAssetBundleOp = new DownloadWebEncryptAssetBundleOperation(true, _fileSystem.DecryptionServices, _bundle, options); _downloadAssetBundleOp = new DownloadEncryptAssetBundleOperation(_bundle, options, true, _fileSystem.DecryptionServices);
_downloadAssetBundleOp.StartOperation(); _downloadAssetBundleOp.StartOperation();
AddChildOperation(_downloadAssetBundleOp); AddChildOperation(_downloadAssetBundleOp);
} }
else else
{ {
_downloadAssetBundleOp = new DownloadWebNormalAssetBundleOperation(_fileSystem.DisableUnityWebCache, _bundle, options); _downloadAssetBundleOp = new DownloadNormalAssetBundleOperation(_bundle, options, _fileSystem.DisableUnityWebCache);
_downloadAssetBundleOp.StartOperation(); _downloadAssetBundleOp.StartOperation();
AddChildOperation(_downloadAssetBundleOp); AddChildOperation(_downloadAssetBundleOp);
} }

View File

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

View File

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

View File

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

View File

@@ -34,20 +34,20 @@ namespace YooAsset
{ {
if (_downloadAssetBundleOp == null) if (_downloadAssetBundleOp == null)
{ {
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60);
string fileLoadPath = _fileSystem.GetWebFileLoadPath(_bundle); string fileLoadPath = _fileSystem.GetWebFileLoadPath(_bundle);
options.MainURL = DownloadSystemHelper.ConvertToWWWPath(fileLoadPath); string mainURL = DownloadSystemHelper.ConvertToWWWPath(fileLoadPath);
options.FallbackURL = options.MainURL; DownloadFileOptions options = new DownloadFileOptions(int.MaxValue, 60);
options.SetURL(mainURL, mainURL);
if (_bundle.Encrypted) if (_bundle.Encrypted)
{ {
_downloadAssetBundleOp = new DownloadWebEncryptAssetBundleOperation(true, _fileSystem.DecryptionServices, _bundle, options); _downloadAssetBundleOp = new DownloadEncryptAssetBundleOperation(_bundle, options, true, _fileSystem.DecryptionServices);
_downloadAssetBundleOp.StartOperation(); _downloadAssetBundleOp.StartOperation();
AddChildOperation(_downloadAssetBundleOp); AddChildOperation(_downloadAssetBundleOp);
} }
else else
{ {
_downloadAssetBundleOp = new DownloadWebNormalAssetBundleOperation(_fileSystem.DisableUnityWebCache, _bundle, options); _downloadAssetBundleOp = new DownloadNormalAssetBundleOperation(_bundle, options, _fileSystem.DisableUnityWebCache);
_downloadAssetBundleOp.StartOperation(); _downloadAssetBundleOp.StartOperation();
AddChildOperation(_downloadAssetBundleOp); AddChildOperation(_downloadAssetBundleOp);
} }

View File

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

View File

@@ -7,6 +7,7 @@ namespace YooAsset
public const string INSTALL_CLEAR_MODE = "INSTALL_CLEAR_MODE"; public const string INSTALL_CLEAR_MODE = "INSTALL_CLEAR_MODE";
public const string REMOTE_SERVICES = "REMOTE_SERVICES"; public const string REMOTE_SERVICES = "REMOTE_SERVICES";
public const string DECRYPTION_SERVICES = "DECRYPTION_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 APPEND_FILE_EXTENSION = "APPEND_FILE_EXTENSION";
public const string DISABLE_CATALOG_FILE = "DISABLE_CATALOG_FILE"; public const string DISABLE_CATALOG_FILE = "DISABLE_CATALOG_FILE";
public const string DISABLE_UNITY_WEB_CACHE = "DISABLE_UNITY_WEB_CACHE"; 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 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 = "COPY_BUILDIN_PACKAGE_MANIFEST";
public const string COPY_BUILDIN_PACKAGE_MANIFEST_DEST_ROOT = "COPY_BUILDIN_PACKAGE_MANIFEST_DEST_ROOT"; 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

@@ -16,15 +16,15 @@ namespace YooAsset
/// <summary> /// <summary>
/// 主资源地址 /// 主资源地址
/// </summary> /// </summary>
public string MainURL { set; get; } public string MainURL { private set; get; }
/// <summary> /// <summary>
/// 备用资源地址 /// 备用资源地址
/// </summary> /// </summary>
public string FallbackURL { set; get; } public string FallbackURL { private set; get; }
/// <summary> /// <summary>
/// 导入的本地文件路径 /// 拷贝的本地文件路径
/// </summary> /// </summary>
public string ImportFilePath { set; get; } public string ImportFilePath { set; get; }
@@ -33,22 +33,32 @@ namespace YooAsset
FailedTryAgain = failedTryAgain; FailedTryAgain = failedTryAgain;
Timeout = timeout; Timeout = timeout;
} }
/// <summary>
/// 设置下载地址
/// </summary>
public void SetURL(string mainURL, string fallbackURL)
{
MainURL = mainURL;
FallbackURL = fallbackURL;
}
/// <summary>
/// 是否有效
/// </summary>
public bool IsValid()
{
if (string.IsNullOrEmpty(MainURL) || string.IsNullOrEmpty(FallbackURL))
return false;
return true;
}
} }
internal abstract class FSDownloadFileOperation : AsyncOperationBase internal abstract class FSDownloadFileOperation : AsyncOperationBase
{ {
public PackageBundle Bundle { private set; get; } public PackageBundle Bundle { private set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
/// <summary>
/// HTTP返回码
/// </summary>
public long HttpCode { protected set; get; }
/// <summary> /// <summary>
/// 当前下载的字节数 /// 当前下载的字节数
/// </summary> /// </summary>
@@ -63,31 +73,8 @@ namespace YooAsset
public FSDownloadFileOperation(PackageBundle bundle) public FSDownloadFileOperation(PackageBundle bundle)
{ {
Bundle = bundle; Bundle = bundle;
RefCount = 0;
HttpCode = 0;
DownloadedBytes = 0; DownloadedBytes = 0;
DownloadProgress = 0; DownloadProgress = 0;
} }
internal override string InternalGetDesc()
{
return $"RefCount : {RefCount}";
}
/// <summary>
/// 减少引用计数
/// </summary>
public virtual void Release()
{
RefCount--;
}
/// <summary>
/// 增加引用计数
/// </summary>
public virtual void Reference()
{
RefCount++;
}
} }
} }

View File

@@ -1,130 +0,0 @@
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal abstract class DefaultDownloadFileOperation : FSDownloadFileOperation
{
protected enum ESteps
{
None,
CheckExists,
CreateRequest,
CheckRequest,
VerifyTempFile,
CheckVerifyTempFile,
TryAgain,
Done,
}
// 下载参数
protected readonly DownloadFileOptions Options;
// 请求相关
protected UnityWebRequest _webRequest;
protected string _requestURL;
protected int _requestCount = 0;
// 超时相关
protected bool _isAbort = false;
protected long _latestDownloadBytes;
protected float _latestDownloadRealtime;
protected float _tryAgainTimer;
// 失败相关
protected int FailedTryAgain;
internal DefaultDownloadFileOperation(PackageBundle bundle, DownloadFileOptions options) : base(bundle)
{
Options = options;
FailedTryAgain = options.FailedTryAgain;
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return Options.FallbackURL;
else
return Options.MainURL;
}
/// <summary>
/// 重置请求字段
/// </summary>
protected void ResetRequestFiled()
{
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
DownloadProgress = 0f;
DownloadedBytes = 0;
// 重置计时器
if (_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
}
/// <summary>
/// 检测请求超时
/// </summary>
protected void CheckRequestTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != DownloadedBytes)
{
_latestDownloadBytes = DownloadedBytes;
_latestDownloadRealtime = UnityEngine.Time.realtimeSinceStartup;
}
float offset = UnityEngine.Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > Options.Timeout)
{
YooLogger.Warning($"Download request timeout : {_requestURL}");
if (_webRequest != null)
_webRequest.Abort();
_isAbort = true;
}
}
}
/// <summary>
/// 检测请求结果
/// </summary>
protected bool CheckRequestResult()
{
HttpCode = _webRequest.responseCode;
#if UNITY_2020_3_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
{
Error = _webRequest.error;
return false;
}
else
{
return true;
}
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
Error = _webRequest.error;
return false;
}
else
{
return true;
}
#endif
}
}
}

View File

@@ -2,12 +2,21 @@
namespace YooAsset namespace YooAsset
{ {
internal abstract class DownloadAssetBundleOperation : DefaultDownloadFileOperation internal abstract class DownloadAssetBundleOperation : AsyncOperationBase
{ {
internal DownloadAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options) : base(bundle, options) /// <summary>
{ /// AssetBundle对象
} /// </summary>
public AssetBundle Result; public AssetBundle Result;
/// <summary>
/// 下载进度
/// </summary>
public float DownloadProgress { protected set; get; } = 0;
/// <summary>
/// 下载大小
/// </summary>
public long DownloadedBytes { protected set; get; } = 0;
} }
} }

View File

@@ -1,71 +0,0 @@

namespace YooAsset
{
internal class DownloadFileWrapper : FSDownloadFileOperation
{
private enum ESteps
{
None,
Download,
Done,
}
private readonly FSDownloadFileOperation _downloadFileOp;
private ESteps _steps = ESteps.None;
internal DownloadFileWrapper(FSDownloadFileOperation downloadFileOp) : base(downloadFileOp.Bundle)
{
_downloadFileOp = downloadFileOp;
}
internal override void InternalStart()
{
_steps = ESteps.Download;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Download)
{
if (IsWaitForAsyncComplete)
_downloadFileOp.WaitForAsyncComplete();
if (_downloadFileOp.Status == EOperationStatus.None)
return;
_downloadFileOp.UpdateOperation();
Progress = _downloadFileOp.Progress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
DownloadProgress = _downloadFileOp.DownloadProgress;
if (_downloadFileOp.IsDone == false)
return;
_steps = ESteps.Done;
Status = _downloadFileOp.Status;
Error = _downloadFileOp.Error;
HttpCode = _downloadFileOp.HttpCode;
}
}
internal override void InternalWaitForAsyncComplete()
{
while (true)
{
if (ExecuteWhileDone())
{
_steps = ESteps.Done;
break;
}
}
}
public override void Release()
{
_downloadFileOp.Release();
}
public override void Reference()
{
_downloadFileOp.Reference();
}
}
}

View File

@@ -1,17 +1,33 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset namespace YooAsset
{ {
internal class DownloadWebEncryptAssetBundleOperation : DownloadAssetBundleOperation internal class DownloadEncryptAssetBundleOperation : DownloadAssetBundleOperation
{ {
protected enum ESteps
{
None,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
private UnityWebDataRequestOperation _unityWebDataRequestOp;
private readonly PackageBundle _bundle;
private readonly DownloadFileOptions _options;
private readonly bool _checkTimeout; private readonly bool _checkTimeout;
private readonly IWebDecryptionServices _decryptionServices; private readonly IWebDecryptionServices _decryptionServices;
private DownloadHandlerBuffer _downloadhandler;
protected int _requestCount = 0;
protected float _tryAgainTimer;
protected int _failedTryAgain;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
internal DownloadWebEncryptAssetBundleOperation(bool checkTimeout, IWebDecryptionServices decryptionServices, PackageBundle bundle, DownloadFileOptions options) : base(bundle, options) internal DownloadEncryptAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options, bool checkTimeout, IWebDecryptionServices decryptionServices)
{ {
_bundle = bundle;
_options = options;
_checkTimeout = checkTimeout; _checkTimeout = checkTimeout;
_decryptionServices = decryptionServices; _decryptionServices = decryptionServices;
} }
@@ -27,118 +43,87 @@ namespace YooAsset
// 创建下载器 // 创建下载器
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
// 获取请求地址 if (_decryptionServices == null)
_requestURL = GetRequestURL(); {
_steps = ESteps.Done;
// 重置变量 Status = EOperationStatus.Failed;
ResetRequestFiled(); Error = $"The {nameof(IWebDecryptionServices)} is null !";
YooLogger.Error(Error);
// 创建下载器 return;
CreateWebRequest(); }
string url = GetRequestURL();
_unityWebDataRequestOp = new UnityWebDataRequestOperation(url, _options.Timeout);
_unityWebDataRequestOp.StartOperation();
if (_checkTimeout == false)
_unityWebDataRequestOp.DontCheckTimeout();
_steps = ESteps.CheckRequest; _steps = ESteps.CheckRequest;
} }
// 检测下载结果 // 检测下载结果
if (_steps == ESteps.CheckRequest) if (_steps == ESteps.CheckRequest)
{ {
DownloadProgress = _webRequest.downloadProgress; _unityWebDataRequestOp.UpdateOperation();
DownloadedBytes = (long)_webRequest.downloadedBytes; Progress = _unityWebDataRequestOp.Progress;
Progress = DownloadProgress; DownloadProgress = _unityWebDataRequestOp.DownloadProgress;
if (_webRequest.isDone == false) DownloadedBytes = _unityWebDataRequestOp.DownloadedBytes;
{ if (_unityWebDataRequestOp.IsDone == false)
if (_checkTimeout)
CheckRequestTimeout();
return; return;
}
// 检查网络错误 // 检查网络错误
if (CheckRequestResult()) if (_unityWebDataRequestOp.Status == EOperationStatus.Succeed)
{ {
if (_decryptionServices == null) AssetBundle assetBundle = LoadEncryptedAssetBundle(_unityWebDataRequestOp.Result);
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(IWebDecryptionServices)} is null !";
YooLogger.Error(Error);
return;
}
var fileData = _downloadhandler.data;
if (fileData == null || fileData.Length == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The download handler data is null or empty !";
YooLogger.Error(Error);
return;
}
AssetBundle assetBundle = LoadEncryptedAssetBundle(fileData);
if (assetBundle == null) if (assetBundle == null)
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = "Download handler asset bundle object is null !"; Error = "Failed load encrypted AssetBundle !";
} }
else else
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Result = assetBundle;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
Result = assetBundle;
} }
} }
else else
{ {
_steps = ESteps.TryAgain; if (_failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_unityWebDataRequestOp.URL} Try again !");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _unityWebDataRequestOp.Error;
YooLogger.Error(Error);
}
} }
// 注意:最终释放请求器
DisposeWebRequest();
} }
// 重新尝试下载 // 重新尝试下载
if (_steps == ESteps.TryAgain) if (_steps == ESteps.TryAgain)
{ {
if (FailedTryAgain <= 0)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
_tryAgainTimer += Time.unscaledDeltaTime; _tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f) if (_tryAgainTimer > 1f)
{ {
FailedTryAgain--; _tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest; _steps = ESteps.CreateRequest;
YooLogger.Warning(Error);
} }
} }
} }
internal override void InternalAbort() internal override void InternalAbort()
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
DisposeWebRequest(); if (_unityWebDataRequestOp != null)
} _unityWebDataRequestOp.AbortOperation();
private void CreateWebRequest()
{
_downloadhandler = new DownloadHandlerBuffer();
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
_webRequest.downloadHandler = _downloadhandler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
//注意引擎底层会自动调用Abort方法
_webRequest.Dispose();
_webRequest = null;
}
} }
/// <summary> /// <summary>
@@ -147,11 +132,24 @@ namespace YooAsset
private AssetBundle LoadEncryptedAssetBundle(byte[] fileData) private AssetBundle LoadEncryptedAssetBundle(byte[] fileData)
{ {
var fileInfo = new WebDecryptFileInfo(); var fileInfo = new WebDecryptFileInfo();
fileInfo.BundleName = Bundle.BundleName; fileInfo.BundleName = _bundle.BundleName;
fileInfo.FileLoadCRC = Bundle.UnityCRC; fileInfo.FileLoadCRC = _bundle.UnityCRC;
fileInfo.FileData = fileData; fileInfo.FileData = fileData;
var decryptResult = _decryptionServices.LoadAssetBundle(fileInfo); var decryptResult = _decryptionServices.LoadAssetBundle(fileInfo);
return decryptResult.Result; return decryptResult.Result;
} }
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
} }
} }

View File

@@ -1,16 +1,33 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset namespace YooAsset
{ {
internal class DownloadWebNormalAssetBundleOperation : DownloadAssetBundleOperation internal class DownloadNormalAssetBundleOperation : DownloadAssetBundleOperation
{ {
protected enum ESteps
{
None,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
private UnityAssetBundleRequestOperation _unityAssetBundleRequestOp;
private readonly PackageBundle _bundle;
private readonly DownloadFileOptions _options;
private readonly bool _disableUnityWebCache; private readonly bool _disableUnityWebCache;
private DownloadHandlerAssetBundle _downloadhandler;
protected int _requestCount = 0;
protected float _tryAgainTimer;
protected int _failedTryAgain;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
internal DownloadWebNormalAssetBundleOperation(bool disableUnityWebCache, PackageBundle bundle, DownloadFileOptions options) : base(bundle, options)
internal DownloadNormalAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options, bool disableUnityWebCache)
{ {
_bundle = bundle;
_options = options;
_disableUnityWebCache = disableUnityWebCache; _disableUnityWebCache = disableUnityWebCache;
} }
internal override void InternalStart() internal override void InternalStart()
@@ -25,120 +42,78 @@ namespace YooAsset
// 创建下载器 // 创建下载器
if (_steps == ESteps.CreateRequest) if (_steps == ESteps.CreateRequest)
{ {
// 获取请求地址 string url = GetRequestURL();
_requestURL = GetRequestURL(); _unityAssetBundleRequestOp = new UnityAssetBundleRequestOperation(_bundle, _disableUnityWebCache, url, _options.Timeout);
_unityAssetBundleRequestOp.StartOperation();
// 重置变量
ResetRequestFiled();
// 创建下载器
CreateWebRequest();
_steps = ESteps.CheckRequest; _steps = ESteps.CheckRequest;
} }
// 检测下载结果 // 检测下载结果
if (_steps == ESteps.CheckRequest) if (_steps == ESteps.CheckRequest)
{ {
DownloadProgress = _webRequest.downloadProgress; _unityAssetBundleRequestOp.UpdateOperation();
DownloadedBytes = (long)_webRequest.downloadedBytes; Progress = _unityAssetBundleRequestOp.Progress;
Progress = DownloadProgress; DownloadedBytes = _unityAssetBundleRequestOp.DownloadedBytes;
if (_webRequest.isDone == false) DownloadProgress = _unityAssetBundleRequestOp.DownloadProgress;
{ if (_unityAssetBundleRequestOp.IsDone == false)
CheckRequestTimeout();
return; return;
}
// 检查网络错误 if (_unityAssetBundleRequestOp.Status == EOperationStatus.Succeed)
if (CheckRequestResult())
{ {
AssetBundle assetBundle = _downloadhandler.assetBundle; _steps = ESteps.Done;
if (assetBundle == null) Status = EOperationStatus.Succeed;
Result = _unityAssetBundleRequestOp.Result;
}
else
{
if (_failedTryAgain > 0)
{ {
_steps = ESteps.Done; _steps = ESteps.TryAgain;
Status = EOperationStatus.Failed; YooLogger.Warning($"Failed download : {_unityAssetBundleRequestOp.URL} Try again !");
Error = "Download handler asset bundle object is null !";
} }
else else
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Result = assetBundle; Status = EOperationStatus.Failed;
Status = EOperationStatus.Succeed; Error = _unityAssetBundleRequestOp.Error;
YooLogger.Error(Error);
} }
} }
else
{
_steps = ESteps.TryAgain;
}
// 注意:最终释放请求器
DisposeWebRequest();
} }
// 重新尝试下载 // 重新尝试下载
if (_steps == ESteps.TryAgain) if (_steps == ESteps.TryAgain)
{ {
if (FailedTryAgain <= 0)
{
Status = EOperationStatus.Failed;
_steps = ESteps.Done;
YooLogger.Error(Error);
return;
}
_tryAgainTimer += Time.unscaledDeltaTime; _tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f) if (_tryAgainTimer > 1f)
{ {
FailedTryAgain--; _tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest; _steps = ESteps.CreateRequest;
YooLogger.Warning(Error);
} }
} }
} }
internal override void InternalAbort() internal override void InternalAbort()
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
DisposeWebRequest(); if (_unityAssetBundleRequestOp != null)
_unityAssetBundleRequestOp.AbortOperation();
} }
private void CreateWebRequest() /// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{ {
_downloadhandler = CreateWebDownloadHandler(); // 轮流返回请求地址
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL); _requestCount++;
_webRequest.downloadHandler = _downloadhandler; if (_requestCount % 2 == 0)
_webRequest.disposeDownloadHandlerOnDispose = true; return _options.FallbackURL;
_webRequest.SendWebRequest();
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
//注意引擎底层会自动调用Abort方法
_webRequest.Dispose();
_webRequest = null;
}
}
private DownloadHandlerAssetBundle CreateWebDownloadHandler()
{
if (_disableUnityWebCache)
{
var downloadhandler = new DownloadHandlerAssetBundle(_requestURL, Bundle.UnityCRC);
#if UNITY_2020_3_OR_NEWER
downloadhandler.autoLoadAssetBundle = false;
#endif
return downloadhandler;
}
else else
{ return _options.MainURL;
// 注意:优先从浏览器缓存里获取文件
// The file hash defining the version of the asset bundle.
Hash128 fileHash = Hash128.Parse(Bundle.FileHash);
var downloadhandler = new DownloadHandlerAssetBundle(_requestURL, fileHash, Bundle.UnityCRC);
#if UNITY_2020_3_OR_NEWER
downloadhandler.autoLoadAssetBundle = false;
#endif
return downloadhandler;
}
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ namespace YooAsset
private long _sceneCreateIndex = 0; private long _sceneCreateIndex = 0;
private IBundleQuery _bundleQuery; private IBundleQuery _bundleQuery;
private int _bundleLoadingMaxConcurrency; private int _bundleLoadingMaxConcurrency;
private bool _webGLForceSyncLoadAsset;
/// <summary> /// <summary>
/// 所属包裹 /// 所属包裹
@@ -43,6 +44,7 @@ namespace YooAsset
public void Initialize(InitializeParameters parameters, IBundleQuery bundleServices) public void Initialize(InitializeParameters parameters, IBundleQuery bundleServices)
{ {
_bundleLoadingMaxConcurrency = parameters.BundleLoadingMaxConcurrency; _bundleLoadingMaxConcurrency = parameters.BundleLoadingMaxConcurrency;
_webGLForceSyncLoadAsset = parameters.WebGLForceSyncLoadAsset;
_bundleQuery = bundleServices; _bundleQuery = bundleServices;
SceneManager.sceneUnloaded += OnSceneUnloaded; SceneManager.sceneUnloaded += OnSceneUnloaded;
} }
@@ -58,7 +60,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 尝试卸载指定资源的资源包(包括依赖资源) /// 尝试卸载指定资源的资源包(包括依赖资源)
/// </summary> /// </summary>
public void TryUnloadUnusedAsset(AssetInfo assetInfo) public void TryUnloadUnusedAsset(AssetInfo assetInfo, int loopCount)
{ {
if (assetInfo.IsInvalid) if (assetInfo.IsInvalid)
{ {
@@ -66,34 +68,39 @@ namespace YooAsset
return; return;
} }
// 卸载主资源包加载器 while (loopCount > 0)
string mainBundleName = _bundleQuery.GetMainBundleName(assetInfo);
var mainLoader = TryGetBundleFileLoader(mainBundleName);
if (mainLoader != null)
{ {
mainLoader.TryDestroyProviders(); loopCount--;
if (mainLoader.CanDestroyLoader())
{
string bundleName = mainLoader.LoadBundleInfo.Bundle.BundleName;
mainLoader.DestroyLoader();
LoaderDic.Remove(bundleName);
}
}
// 卸载依赖资源包加载器 // 卸载资源包加载器
string[] dependBundleNames = _bundleQuery.GetDependBundleNames(assetInfo); string mainBundleName = _bundleQuery.GetMainBundleName(assetInfo);
foreach (var dependBundleName in dependBundleNames) var mainLoader = TryGetBundleFileLoader(mainBundleName);
{ if (mainLoader != null)
var dependLoader = TryGetBundleFileLoader(dependBundleName);
if (dependLoader != null)
{ {
if (dependLoader.CanDestroyLoader()) mainLoader.TryDestroyProviders();
if (mainLoader.CanDestroyLoader())
{ {
string bundleName = dependLoader.LoadBundleInfo.Bundle.BundleName; string bundleName = mainLoader.LoadBundleInfo.Bundle.BundleName;
dependLoader.DestroyLoader(); mainLoader.DestroyLoader();
LoaderDic.Remove(bundleName); LoaderDic.Remove(bundleName);
} }
} }
// 卸载依赖资源包加载器
string[] dependBundleNames = _bundleQuery.GetDependBundleNames(assetInfo);
foreach (var dependBundleName in dependBundleNames)
{
var dependLoader = TryGetBundleFileLoader(dependBundleName);
if (dependLoader != null)
{
if (dependLoader.CanDestroyLoader())
{
string bundleName = dependLoader.LoadBundleInfo.Bundle.BundleName;
dependLoader.DestroyLoader();
LoaderDic.Remove(bundleName);
}
}
}
} }
} }
@@ -321,6 +328,10 @@ namespace YooAsset
{ {
return BundleLoadingCounter >= _bundleLoadingMaxConcurrency; return BundleLoadingCounter >= _bundleLoadingMaxConcurrency;
} }
internal bool WebGLForceSyncLoadAsset()
{
return _webGLForceSyncLoadAsset;
}
private LoadBundleFileOperation CreateBundleFileLoaderInternal(BundleInfo bundleInfo) private LoadBundleFileOperation CreateBundleFileLoaderInternal(BundleInfo bundleInfo)
{ {

View File

@@ -44,7 +44,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 序列化(二进制文件) /// 序列化(二进制文件)
/// </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)) using (FileStream fs = new FileStream(savePath, FileMode.Create))
{ {
@@ -96,9 +96,20 @@ namespace YooAsset
buffer.WriteInt32Array(packageBundle.DependBundleIDs); buffer.WriteInt32Array(packageBundle.DependBundleIDs);
} }
// 写入文件流 // 清单处理操作
buffer.WriteToStream(fs); if (services != null)
fs.Flush(); {
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>
/// 反序列化(二进制文件) /// 反序列化(二进制文件)
/// </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(); uint fileSign = buffer.ReadUInt32();

View File

@@ -366,7 +366,7 @@ namespace YooAsset
foreach (var downloader in _downloaders) foreach (var downloader in _downloaders)
{ {
downloader.Release(); downloader.AbortOperation();
} }
} }
} }

View File

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

View File

@@ -361,21 +361,21 @@ namespace YooAsset
/// 资源回收 /// 资源回收
/// 说明:尝试卸载指定的资源 /// 说明:尝试卸载指定的资源
/// </summary> /// </summary>
public void TryUnloadUnusedAsset(string location) public void TryUnloadUnusedAsset(string location, int loopCount = 10)
{ {
DebugCheckInitialize(); DebugCheckInitialize();
AssetInfo assetInfo = ConvertLocationToAssetInfo(location, null); AssetInfo assetInfo = ConvertLocationToAssetInfo(location, null);
_resourceManager.TryUnloadUnusedAsset(assetInfo); _resourceManager.TryUnloadUnusedAsset(assetInfo, loopCount);
} }
/// <summary> /// <summary>
/// 资源回收 /// 资源回收
/// 说明:尝试卸载指定的资源 /// 说明:尝试卸载指定的资源
/// </summary> /// </summary>
public void TryUnloadUnusedAsset(AssetInfo assetInfo) public void TryUnloadUnusedAsset(AssetInfo assetInfo, int loopCount = 10)
{ {
DebugCheckInitialize(); DebugCheckInitialize();
_resourceManager.TryUnloadUnusedAsset(assetInfo); _resourceManager.TryUnloadUnusedAsset(assetInfo, loopCount);
} }
#endregion #endregion

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

View File

@@ -1,6 +1,18 @@
 
namespace YooAsset namespace YooAsset
{ {
public struct EncryptFileInfo
{
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 文件路径
/// </summary>
public string FileLoadPath;
}
public struct EncryptResult public struct EncryptResult
{ {
/// <summary> /// <summary>
@@ -14,19 +26,6 @@ namespace YooAsset
public byte[] EncryptedData; public byte[] EncryptedData;
} }
public struct EncryptFileInfo
{
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 文件路径
/// </summary>
public string FileLoadPath;
}
public interface IEncryptionServices public interface IEncryptionServices
{ {
EncryptResult Encrypt(EncryptFileInfo fileInfo); 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; _index = 0;
} }
/// <summary>
/// 获取有效数据
/// </summary>
public byte[] GetBytes()
{
byte[] newArray = new byte[_index];
Buffer.BlockCopy(_buffer, 0, newArray, 0, _index);
return newArray;
}
/// <summary> /// <summary>
/// 将有效数据写入文件流 /// 将有效数据写入文件流
/// </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 // 加载补丁清单1
byte[] bytesData1 = FileUtility.ReadAllBytes(_manifestPath1); byte[] bytesData1 = FileUtility.ReadAllBytes(_manifestPath1);
PackageManifest manifest1 = ManifestTools.DeserializeFromBinary(bytesData1); PackageManifest manifest1 = ManifestTools.DeserializeFromBinary(bytesData1, null); //TODO 自行处理解密
// 加载补丁清单1 // 加载补丁清单1
byte[] bytesData2 = FileUtility.ReadAllBytes(_manifestPath2); byte[] bytesData2 = FileUtility.ReadAllBytes(_manifestPath2);
PackageManifest manifest2 = ManifestTools.DeserializeFromBinary(bytesData2); PackageManifest manifest2 = ManifestTools.DeserializeFromBinary(bytesData2, null); //TODO 自行处理解密
// 拷贝文件列表 // 拷贝文件列表
foreach (var bundle2 in manifest2.BundleList) foreach (var bundle2 in manifest2.BundleList)

View File

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

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

View File

@@ -0,0 +1,42 @@
#if UNITY_ANDROID && GOOGLE_PLAY
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
using System.Linq;
using System;
public static class GooglePlayFileSystemCreater
{
public static FileSystemParameters CreateFileSystemParameters(string packageRoot)
{
string fileSystemClass = $"{nameof(GooglePlayFileSystem)},YooAsset.MiniGame";
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
return fileSystemParams;
}
}
/// <summary>
/// 兼容谷歌Play Asset Delivery的文件系统
/// </summary>
internal class GooglePlayFileSystem : DefaultBuildinFileSystem
{
public GooglePlayFileSystem()
{
}
public override FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
{
if (bundle.BundleType == (int)EBuildBundleType.AssetBundle)
{
var operation = new GPFSLoadAssetBundleOperation(this, bundle);
return operation;
}
else
{
string error = $"{nameof(GooglePlayFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,85 @@
#if UNITY_ANDROID && GOOGLE_PLAY
using System.IO;
using UnityEngine;
using YooAsset;
using Google.Play.AssetDelivery;
internal class GPFSLoadAssetBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadAssetBundle,
CheckResult,
Done,
}
private readonly GooglePlayFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private PlayAssetBundleRequest _bundleRequest;
private ESteps _steps = ESteps.None;
internal GPFSLoadAssetBundleOperation(GooglePlayFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadAssetBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadAssetBundle)
{
if (_bundle.Encrypted)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(GooglePlayFileSystem)} not support bundle encrypted !";
YooLogger.Error(Error);
return;
}
_bundleRequest = PlayAssetDelivery.RetrieveAssetBundleAsync(_bundle.FileName);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_bundleRequest.IsDone == false)
return;
if (_bundleRequest.Error != AssetDeliveryErrorCode.NoError)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load delivery asset bundle file : {_bundle.BundleName} Error : {_bundleRequest.Error}";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
Result = new AssetBundleResult(_fileSystem, _bundle, _bundleRequest.AssetBundle, null);
}
}
}
internal override void InternalWaitForAsyncComplete()
{
if (_steps != ESteps.Done)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(GooglePlayFileSystem)} not support sync load method !";
UnityEngine.Debug.LogError(Error);
}
}
}
#endif

View File

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

View File

@@ -41,7 +41,7 @@ internal class TTFSLoadBundleOperation : FSLoadBundleOperation
if (_bundle.Encrypted) if (_bundle.Encrypted)
{ {
_downloadAssetBundleOp = new DownloadWebEncryptAssetBundleOperation(false, _fileSystem.DecryptionServices, _bundle, options); _downloadAssetBundleOp = new DownloadEncryptAssetBundleOperation(false, _fileSystem.DecryptionServices, _bundle, options);
_downloadAssetBundleOp.StartOperation(); _downloadAssetBundleOp.StartOperation();
AddChildOperation(_downloadAssetBundleOp); AddChildOperation(_downloadAssetBundleOp);
} }

Some files were not shown because too many files have changed in this diff Show More