Compare commits

...

84 Commits

Author SHA1 Message Date
hevinci
b421e7d2f8 Update CHANGELOG.md 2024-07-31 12:06:23 +08:00
hevinci
0e7c14abde Update package.json 2024-07-31 12:06:15 +08:00
hevinci
caf072ed9b Update DefaultBuildinFileSystemBuild.cs 2024-07-31 12:02:07 +08:00
hevinci
51f2709956 Update EditorTools.cs 2024-07-31 12:01:29 +08:00
hevinci
6680a6450b fix #325
适配unity2019引擎
2024-07-24 10:12:42 +08:00
hevinci
dc119b26c7 fix #321 2024-07-19 12:02:43 +08:00
hevinci
2cbfca4f3b update extension sample
着色器变种文件增加内部排序
2024-07-15 18:51:32 +08:00
何冠峰
7d8fce6f46 Update CHANGELOG.md 2024-07-10 16:54:45 +08:00
何冠峰
13ad50aef5 Update package.json 2024-07-10 16:54:43 +08:00
何冠峰
30245b3668 update extension sample 2024-07-10 16:50:19 +08:00
何冠峰
589eea7cf3 update file system
统一所有PlayMode的初始化行为
2024-07-09 23:37:20 +08:00
何冠峰
24c5108ce1 update asset bundle collector
适配团结引擎
2024-07-09 16:33:41 +08:00
何冠峰
21fbb01ce4 merge #317
根据NETAnalyzers调整代码
2024-07-08 18:54:07 +08:00
何冠峰
e664f20d34 update extension sample 2024-07-08 17:36:39 +08:00
何冠峰
b0ce14dc0e update file system
IFileSystem新增ReadFileData方法
2024-07-08 17:36:25 +08:00
何冠峰
d2b38cbc1b Update CHANGELOG.md 2024-07-07 18:04:21 +08:00
何冠峰
a6d978090c Update package.json 2024-07-07 18:04:19 +08:00
何冠峰
f9d40987eb update extension sample 2024-07-07 16:16:00 +08:00
何冠峰
cab710493e update file system 2024-07-07 16:15:42 +08:00
何冠峰
9970cf704b update space shooter 2024-07-07 16:02:22 +08:00
何冠峰
260867b588 update operation logic 2024-07-07 16:01:55 +08:00
何冠峰
25231ecd32 update resource manager 2024-07-07 09:45:01 +08:00
何冠峰
b282515c39 update extension sample 2024-07-07 00:52:50 +08:00
何冠峰
bafd15571a update file system 2024-07-07 00:52:17 +08:00
何冠峰
481711fd75 update space shooter 2024-07-05 20:21:51 +08:00
何冠峰
d09b52301a update extension sample 2024-07-05 20:20:38 +08:00
何冠峰
0c77ef628f update file system 2024-07-05 20:20:27 +08:00
何冠峰
54f585c67a update extension sample 2024-07-05 19:29:50 +08:00
何冠峰
a9e5e7fdd3 update file system 2024-07-05 19:29:34 +08:00
何冠峰
b151f968d7 update space shooter 2024-07-05 15:10:52 +08:00
何冠峰
86ef93caa3 update extension sample 2024-07-05 15:10:34 +08:00
何冠峰
75511397d6 update file system 2024-07-05 15:10:07 +08:00
何冠峰
db8d09d0d6 update extension sample
增加微信小游戏文件系统范例
2024-07-04 22:56:45 +08:00
何冠峰
02d70a476d update file system 2024-07-04 22:55:58 +08:00
何冠峰
9420f8561f update web file system 2024-07-04 21:59:24 +08:00
何冠峰
d43eb821b9 update sapce shooter 2024-07-04 20:49:18 +08:00
何冠峰
b82ede8bde update samples 2024-07-04 20:49:07 +08:00
何冠峰
ff02da5c54 refactor the runtime code
重构了运行时代码,支持全新的文件系统。
2024-07-04 20:36:26 +08:00
hevinci
2987d356b6 fix #308 2024-05-27 10:42:24 +08:00
hevinci
dc5f0b151b Update CHANGELOG.md 2024-05-16 17:20:58 +08:00
hevinci
dd5bcc3d9d Update package.json 2024-05-16 17:20:45 +08:00
hevinci
80188ae6e6 fix #295 2024-05-10 10:57:06 +08:00
hevinci
05e77dc166 update dependencies
SBP依赖库升级至2.1.3版本
2024-05-09 14:05:53 +08:00
hevinci
b9b8f8e170 style code 2024-04-26 16:06:49 +08:00
hevinci
c9cc09cbed fix #289 2024-04-26 16:05:37 +08:00
hevinci
bef90bf3b8 perf : check build pipeline parameter type 2024-04-26 16:05:13 +08:00
hevinci
a369efa429 fix #276 2024-04-12 11:25:12 +08:00
hevinci
370329b07d refactor : wechat game support
提供对微信小游戏缓存的查询接口
2024-04-11 19:51:34 +08:00
hevinci
e743a15fbc update extension sample 2024-04-09 20:09:12 +08:00
hevinci
10c8b52092 add packages files 2024-04-09 19:15:35 +08:00
hevinci
1461b91a94 fix #268
修复了挂起场景未解除状态前无法卸载的问题。
2024-04-03 17:14:16 +08:00
hevinci
b5ffd5005a fix #269
优化场景挂起流程,支持中途取消挂起操作。
2024-04-03 17:11:11 +08:00
hevinci
f06bd83dc3 style : add summry 2024-04-02 17:26:57 +08:00
hevinci
a1450ee78a refactor : build System Stability
工具类新增了FileSHA1Safely,FileMD5Safely,FileCRC32Safely等方法。
2024-04-02 13:04:11 +08:00
hevinci
4c619778c3 feat : support open harmony
支持华为鸿蒙系统
2024-03-13 15:50:46 +08:00
hevinci
4e8840cd93 update space shooter 2024-03-12 11:12:39 +08:00
hevinci
0a709f741a feat : asset bundle collector config upgrade compatible 2024-03-12 11:12:13 +08:00
hevinci
ef8229981e feat : add IIgnoreRule interface
支持自定义过滤规则
移除了IgnoreDefaultType收集参数
2024-03-12 10:33:54 +08:00
hevinci
2a5a2626a4 feat : add load scene sync method 2024-03-08 15:39:25 +08:00
hevinci
f4ddaedbf4 feat : add load scene sync method 2024-03-08 14:23:07 +08:00
hevinci
42104eb944 perf : check collector error 2024-03-08 11:39:48 +08:00
hevinci
fadc8e6fd6 feat : add shader pack rule and filter rule 2024-03-08 11:38:29 +08:00
hevinci
81747462b1 feat : add load scene sync method 2024-03-08 11:06:48 +08:00
何冠峰
c01adad2a0 Merge pull request #245 from absences/dev
fix path error
2024-03-04 11:13:47 +08:00
何冠峰
e598d60439 Merge pull request #249 from ZensYue/dev
移除场景成功之后再尝试卸载ab包
2024-03-04 11:12:45 +08:00
e
929cd23f35 移除场景成功之后再尝试卸载ab包 2024-03-03 23:41:28 +08:00
unknown
d1aca5b675 fix path error 2024-02-28 10:06:45 +08:00
hevinci
b67868868d style : correct typos 2024-02-26 17:42:04 +08:00
hevinci
af3bf8448c style : change file to unicode 2024-02-26 14:29:36 +08:00
hevinci
4170c60f0c style : The hash utility class is exposed 2024-02-21 10:10:37 +08:00
hevinci
0a7a883aae fix #244 2024-02-20 11:31:27 +08:00
hevinci
88a1184877 perf : optimize package manifest deserialize 2024-02-20 10:04:10 +08:00
hevinci
c7329fcab5 feat : remove space character for bundle name
移除资源包名里的空格字符
2024-02-20 09:55:49 +08:00
hevinci
6eb9a90a03 feat : add GetAllCacheFileInfosAsync method 2024-02-18 12:11:29 +08:00
hevinci
7586882a97 fix #236 2024-02-01 18:41:16 +08:00
hevinci
6f13c021b9 Update CHANGELOG.md 2024-01-17 12:11:25 +08:00
hevinci
5f30c92d44 Update package.json 2024-01-17 12:11:17 +08:00
hevinci
3e6c55d981 style : code comment 2024-01-10 15:04:29 +08:00
hevinci
de36f984d7 style : change macro name 2024-01-03 16:44:48 +08:00
hevinci
95328fe1a6 feat : wechat game cache query 2024-01-03 16:24:02 +08:00
hevinci
1fb78185ff feat : support share pack rule
支持共享资源打包规则
2024-01-03 15:13:28 +08:00
hevinci
58f9aea979 fix #223 2024-01-02 11:46:29 +08:00
hevinci
4d4bb1e34f fix #223 2024-01-02 11:06:50 +08:00
hevinci
6e1978ec10 fix #224 2024-01-02 10:35:41 +08:00
488 changed files with 12029 additions and 8432 deletions

1
.gitignore vendored
View File

@@ -20,7 +20,6 @@
/Assets/StreamingAssets.meta
/Assets/Samples
/Assets/Samples.meta
/Packages
/UserSettings

View File

@@ -2,6 +2,141 @@
All notable changes to this package will be documented in this file.
## [2.2.2-preview] - 2024-07-31
### Fixed
- (#321) 修复了在Unity2022里编辑器下离线模式运行失败的问题。
- (#325) 修复了在Unity2019里编译报错问题。
## [2.2.1-preview] - 2024-07-10
统一了所有PlayMode的初始化逻辑EditorSimulateMode和OfflinePlayMode初始化不再主动加载资源清单
### Added
- 新增了IFileSystem.ReadFileData方法支持原生文件自定义获取文本和二进制数据。
### Improvements
- 优化了DefaultWebFileSystem和DefaultBuildFileSystem文件系统的内部初始化逻辑。
## [2.2.0-preview] - 2024-07-07
重构了运行时代码新增了文件系统接口IFileSystem方便开发者扩展特殊需求。
新增微信小游戏文件系统示例代码详细见Extension Sample/Runtime/WechatFileSystem
### Added
- 新增了ResourcePackage.DestroyAsync方法
- 新增了FileSystemParameters类帮助初始化文件系统
内置了编辑器文件系统参数内置文件系统参数缓存文件系统参数Web文件系统参数。
```csharp
public class FileSystemParameters
{
/// <summary>
/// 文件系统类
/// </summary>
public string FileSystemClass { private set; get; }
/// <summary>
/// 文件系统的根目录
/// </summary>
public string RootDirectory { private set; get; }
/// <summary>
/// 添加自定义参数
/// </summary>
public void AddParameter(string name, object value)
}
```
### Changed
- 重构了InitializeParameters初始化参数
- 重命名YooAssets.DestroyPackage方法为RemovePackage
- 重命名ResourcePackage.UpdatePackageVersionAsync方法为RequestPackageVersionAsync
- 重命名ResourcePackage.UnloadUnusedAssets方法为UnloadUnusedAssetsAsync
- 重命名ResourcePackage.ForceUnloadAllAssets方法为UnloadAllAssetsAsync
- 重命名ResourcePackage.ClearUnusedCacheFilesAsync方法为ClearUnusedBundleFilesAsync
- 重命名ResourcePackage.ClearAllCacheFilesAsync方法为ClearAllBundleFilesAsync
### Removed
- 移除了YooAssets.Destroy方法
- 移除了YooAssets.SetDownloadSystemClearFileResponseCode方法
- 移除了YooAssets.SetCacheSystemDisableCacheOnWebGL方法
- 移除了ResourcePackage.GetPackageBuildinRootDirectory方法
- 移除了ResourcePackage.GetPackageSandboxRootDirectory方法
- 移除了ResourcePackage.ClearPackageSandbox方法
- 移除了IBuildinQueryServices接口
- 移除了IDeliveryLoadServices接口
- 移除了IDeliveryQueryServices接口
## [2.1.2] - 2024-05-16
SBP库依赖版本升级至2.1.3
### Fixed
- (#236) 修复了资源配置界面AutoCollectShader复选框没有刷新的问题。
- (#244) 修复了导入器在安卓平台导入本地下载的资源失败的问题。
- (#268) 修复了挂起场景未解除状态前无法卸载的问题。
- (#269) 优化场景挂起流程,支持中途取消挂起操作。
- (#276) 修复了HostPlayMode模式下如果内置清单是最新版本每次运行都会触发拷贝行为。
- (#289) 修复了Unity2019版本脚本IWebRequester编译报错。
- (#295) 解决了在安卓移动平台,华为和三星真机上有极小概率加载资源包失败 : Unable to open archive file
### Added
- 新增GetAllCacheFileInfosOperation()获取缓存文件信息的方法。
- 新增LoadSceneSync()同步加载场景的方法。
- 新增IIgnoreRule接口资源收集流程可以自定义。
- 新增IWechatQueryServices接口用于微信平台本地文件查询。
后续将会通过虚拟文件系统来支持!
### Changed
- 调整了UnloadSceneOperation代码里场景的卸载顺序。
### Improvements
- 优化了资源清单的解析过程。
- 移除资源包名里的空格字符。
- 支持华为鸿蒙系统。
## [2.1.1] - 2024-01-17
### Fixed
- (#224) 修复了编辑器模式打包时 SimulateBuild 报错的问题。
- (#223) 修复了资源构建界面读取配置导致的报错问题。
### Added
- 支持共享资源打包规则,可以定制化独立的构建规则。
```c#
public class BuildParameters
{
/// <summary>
/// 是否启用共享资源打包
/// </summary>
public bool EnableSharePackRule = false;
}
```
- 微信小游戏平台,资源下载器支持底层缓存查询。
## [2.1.0] - 2023-12-27
升级了 Scriptable build pipeline (SBP) 的版本,来解决图集引用的精灵图片冗余问题。

View File

@@ -9,7 +9,7 @@ namespace YooAsset.Editor
public static class AssetBundleBuilderHelper
{
/// <summary>
/// 获取默认的输出根
/// 获取默认的输出根
/// </summary>
public static string GetDefaultBuildOutputRoot()
{

View File

@@ -8,8 +8,11 @@ namespace YooAsset.Editor
/// <summary>
/// 模拟构建
/// </summary>
public static string SimulateBuild(string buildPipelineName, string packageName)
public static SimulateBuildResult SimulateBuild(string buildPipelineName, string packageName)
{
string packageVersion = "Simulate";
BuildResult buildResult;
if (buildPipelineName == EBuildPipeline.BuiltinBuildPipeline.ToString())
{
BuiltinBuildParameters buildParameters = new BuiltinBuildParameters();
@@ -19,23 +22,13 @@ namespace YooAsset.Editor
buildParameters.BuildTarget = EditorUserBuildSettings.activeBuildTarget;
buildParameters.BuildMode = EBuildMode.SimulateBuild;
buildParameters.PackageName = packageName;
buildParameters.PackageVersion = "Simulate";
buildParameters.PackageVersion = packageVersion;
buildParameters.FileNameStyle = EFileNameStyle.HashName;
buildParameters.BuildinFileCopyOption = EBuildinFileCopyOption.None;
buildParameters.BuildinFileCopyParams = string.Empty;
BuiltinBuildPipeline pipeline = new BuiltinBuildPipeline();
var buildResult = pipeline.Run(buildParameters, false);
if (buildResult.Success)
{
string manifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string manifestFilePath = $"{buildResult.OutputPackageDirectory}/{manifestFileName}";
return manifestFilePath;
}
else
{
return null;
}
buildResult = pipeline.Run(buildParameters, false);
}
else if (buildPipelineName == EBuildPipeline.ScriptableBuildPipeline.ToString())
{
@@ -46,23 +39,13 @@ namespace YooAsset.Editor
buildParameters.BuildTarget = EditorUserBuildSettings.activeBuildTarget;
buildParameters.BuildMode = EBuildMode.SimulateBuild;
buildParameters.PackageName = packageName;
buildParameters.PackageVersion = "Simulate";
buildParameters.PackageVersion = packageVersion;
buildParameters.FileNameStyle = EFileNameStyle.HashName;
buildParameters.BuildinFileCopyOption = EBuildinFileCopyOption.None;
buildParameters.BuildinFileCopyParams = string.Empty;
ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true);
if (buildResult.Success)
{
string manifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string manifestFilePath = $"{buildResult.OutputPackageDirectory}/{manifestFileName}";
return manifestFilePath;
}
else
{
return null;
}
buildResult = pipeline.Run(buildParameters, true);
}
else if (buildPipelineName == EBuildPipeline.RawFileBuildPipeline.ToString())
{
@@ -73,28 +56,30 @@ namespace YooAsset.Editor
buildParameters.BuildTarget = EditorUserBuildSettings.activeBuildTarget;
buildParameters.BuildMode = EBuildMode.SimulateBuild;
buildParameters.PackageName = packageName;
buildParameters.PackageVersion = "Simulate";
buildParameters.PackageVersion = packageVersion;
buildParameters.FileNameStyle = EFileNameStyle.HashName;
buildParameters.BuildinFileCopyOption = EBuildinFileCopyOption.None;
buildParameters.BuildinFileCopyParams = string.Empty;
RawFileBuildPipeline pipeline = new RawFileBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true);
if (buildResult.Success)
{
string manifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string manifestFilePath = $"{buildResult.OutputPackageDirectory}/{manifestFileName}";
return manifestFilePath;
}
else
{
return null;
}
buildResult = pipeline.Run(buildParameters, true);
}
else
{
throw new System.NotImplementedException(buildPipelineName);
}
// 返回结果
if (buildResult.Success)
{
SimulateBuildResult reulst = new SimulateBuildResult();
reulst.PackageRootDirectory = buildResult.OutputPackageDirectory;
return reulst;
}
else
{
return null;
}
}
}
}

View File

@@ -70,13 +70,14 @@ namespace YooAsset.Editor
}
/// <summary>
/// 设置为统一的着色器包名
/// 设置资源包名
/// </summary>
public void SetShaderBundleName(string packageName, bool uniqueBundleName)
public void SetBundleName(string bundleName)
{
// 获取着色器打包规则结果
PackRuleResult shaderPackRuleResult = DefaultPackRule.CreateShadersPackRuleResult();
BundleName = shaderPackRuleResult.GetBundleName(packageName, uniqueBundleName);
if (HasBundleName())
throw new System.Exception("Should never get here !");
BundleName = bundleName;
}
/// <summary>

View File

@@ -142,7 +142,7 @@ namespace YooAsset.Editor
/// </summary>
public UnityEditor.AssetBundleBuild CreatePipelineBuild()
{
// 注意:我们不支持AssetBundle的变种机制
// 注意:我们不支持AssetBundle的变种机制
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = BundleName;
build.assetBundleVariant = string.Empty;

View File

@@ -47,6 +47,11 @@ namespace YooAsset.Editor
public string PackageVersion;
/// <summary>
/// 是否启用共享资源打包
/// </summary>
public bool EnableSharePackRule = false;
/// <summary>
/// 验证构建结果
/// </summary>

View File

@@ -180,9 +180,9 @@ namespace YooAsset.Editor
for (int index = 0; index < manifest.BundleList.Count; index++)
{
var packageBundle = manifest.BundleList[index];
if (_cacheBundleTags.ContainsKey(index))
if (_cacheBundleTags.TryGetValue(index, out var value))
{
packageBundle.Tags = _cacheBundleTags[index].ToArray();
packageBundle.Tags = value.ToArray();
}
else
{

View File

@@ -31,16 +31,18 @@ namespace YooAsset.Editor
buildReport.Summary.BuildMode = buildParameters.BuildMode;
buildReport.Summary.BuildPackageName = buildParameters.PackageName;
buildReport.Summary.BuildPackageVersion = buildParameters.PackageVersion;
// 收集器配置
buildReport.Summary.UniqueBundleName = buildMapContext.Command.UniqueBundleName;
buildReport.Summary.EnableAddressable = buildMapContext.Command.EnableAddressable;
buildReport.Summary.LocationToLower = buildMapContext.Command.LocationToLower;
buildReport.Summary.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID;
buildReport.Summary.IgnoreDefaultType = buildMapContext.Command.IgnoreDefaultType;
buildReport.Summary.IgnoreRuleName = buildMapContext.Command.IgnoreRule.GetType().FullName;
buildReport.Summary.AutoCollectShaders = buildMapContext.Command.AutoCollectShaders;
buildReport.Summary.EncryptionClassName = buildParameters.EncryptionServices == null ?
"null" : buildParameters.EncryptionServices.GetType().FullName;
// 构建参数
buildReport.Summary.EnableSharePackRule = buildParameters.EnableSharePackRule;
buildReport.Summary.EncryptionClassName = buildParameters.EncryptionServices == null ? "null" : buildParameters.EncryptionServices.GetType().FullName;
if (buildParameters.BuildPipeline == nameof(BuiltinBuildPipeline))
{
var builtinBuildParameters = buildParameters as BuiltinBuildParameters;

View File

@@ -26,7 +26,7 @@ namespace YooAsset.Editor
{
EncryptFileInfo fileInfo = new EncryptFileInfo();
fileInfo.BundleName = bundleInfo.BundleName;
fileInfo.FilePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
fileInfo.FileLoadPath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
var encryptResult = encryptionServices.Encrypt(fileInfo);
if (encryptResult.Encrypted)
{

View File

@@ -56,9 +56,9 @@ namespace YooAsset.Editor
string bundleName = collectAssetInfo.BundleName;
foreach (var dependAsset in collectAssetInfo.DependAssets)
{
if (allBuildAssetInfos.ContainsKey(dependAsset.AssetPath))
if (allBuildAssetInfos.TryGetValue(dependAsset.AssetPath, out var value))
{
allBuildAssetInfos[dependAsset.AssetPath].AddReferenceBundleName(bundleName);
value.AddReferenceBundleName(bundleName);
}
else
{
@@ -86,23 +86,45 @@ namespace YooAsset.Editor
// 6. 自动收集所有依赖的着色器
if (collectResult.Command.AutoCollectShaders)
{
// 获取着色器打包规则结果
PackRuleResult shaderPackRuleResult = DefaultPackRule.CreateShadersPackRuleResult();
string shaderBundleName = shaderPackRuleResult.GetBundleName(collectResult.Command.PackageName, collectResult.Command.UniqueBundleName);
foreach (var buildAssetInfo in allBuildAssetInfos.Values)
{
if (buildAssetInfo.CollectorType == ECollectorType.None)
{
if (buildAssetInfo.AssetInfo.IsShaderAsset())
{
buildAssetInfo.SetShaderBundleName(collectResult.Command.PackageName, collectResult.Command.UniqueBundleName);
buildAssetInfo.SetBundleName(shaderBundleName);
}
}
}
}
// 7. 记录关键信息
// 7. 计算共享资源的包名
if (buildParameters.EnableSharePackRule)
{
PreProcessPackShareBundle(buildParameters, collectResult.Command, allBuildAssetInfos);
foreach (var buildAssetInfo in allBuildAssetInfos.Values)
{
if (buildAssetInfo.HasBundleName() == false)
{
PackRuleResult packRuleResult = GetShareBundleName(buildAssetInfo);
if (packRuleResult.IsValid())
{
string shareBundleName = packRuleResult.GetShareBundleName(collectResult.Command.PackageName, collectResult.Command.UniqueBundleName);
buildAssetInfo.SetBundleName(shareBundleName);
}
}
}
PostProcessPackShareBundle();
}
// 8. 记录关键信息
context.AssetFileCount = allBuildAssetInfos.Count;
context.Command = collectResult.Command;
// 8. 移除不参与构建的资源
// 9. 移除不参与构建的资源
List<BuildAssetInfo> removeBuildList = new List<BuildAssetInfo>();
foreach (var buildAssetInfo in allBuildAssetInfos.Values)
{
@@ -114,7 +136,7 @@ namespace YooAsset.Editor
allBuildAssetInfos.Remove(removeValue.AssetInfo.AssetPath);
}
// 9. 构建资源列表
// 10. 构建资源列表
var allPackAssets = allBuildAssetInfos.Values.ToList();
if (allPackAssets.Count == 0)
{
@@ -177,5 +199,31 @@ namespace YooAsset.Editor
allCollectAssets.Remove(removeValue);
}
}
#region
/// <summary>
/// 共享资源打包前置处理
/// </summary>
protected virtual void PreProcessPackShareBundle(BuildParameters buildParameters, CollectCommand command, Dictionary<string, BuildAssetInfo> allBuildAssetInfos)
{
}
/// <summary>
/// 共享资源打包后置处理
/// </summary>
protected virtual void PostProcessPackShareBundle()
{
}
/// <summary>
/// 获取共享资源包名称
/// </summary>
protected virtual PackRuleResult GetShareBundleName(BuildAssetInfo buildAssetInfo)
{
string bundleName = Path.GetDirectoryName(buildAssetInfo.AssetInfo.AssetPath);
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
return result;
}
#endregion
}
}

View File

@@ -8,8 +8,15 @@ namespace YooAsset.Editor
{
public BuildResult Run(BuildParameters buildParameters, bool enableLog)
{
AssetBundleBuilder builder = new AssetBundleBuilder();
return builder.Run(buildParameters, GetDefaultBuildPipeline(), enableLog);
if (buildParameters is BuiltinBuildParameters)
{
AssetBundleBuilder builder = new AssetBundleBuilder();
return builder.Run(buildParameters, GetDefaultBuildPipeline(), enableLog);
}
else
{
throw new Exception($"Invalid build parameter type : {buildParameters.GetType().Name}");
}
}
/// <summary>

View File

@@ -14,7 +14,7 @@ namespace YooAsset.Editor
protected override string[] GetBundleDepends(BuildContext context, string bundleName)
{
return new string[] { };
return Array.Empty<string>();
}
}
}

View File

@@ -16,6 +16,13 @@ namespace YooAsset.Editor
// 检测基础构建参数
buildParametersContext.CheckBuildParameters();
// 检测不被支持的参数
if (buildParameters.EnableSharePackRule)
{
string message = BuildLogger.GetErrorMessage(ErrorCode.BuildPipelineNotSupportSharePackRule, $"{nameof(EBuildPipeline.RawFileBuildPipeline)} not support share pack rule !");
throw new Exception(message);
}
// 检测不被支持的构建模式
if (buildParameters.BuildMode == EBuildMode.DryRunBuild)
{

View File

@@ -11,8 +11,15 @@ namespace YooAsset.Editor
{
public BuildResult Run(BuildParameters buildParameters, bool enableLog)
{
AssetBundleBuilder builder = new AssetBundleBuilder();
return builder.Run(buildParameters, GetDefaultBuildPipeline(), enableLog);
if (buildParameters is RawFileBuildParameters)
{
AssetBundleBuilder builder = new AssetBundleBuilder();
return builder.Run(buildParameters, GetDefaultBuildPipeline(), enableLog);
}
else
{
throw new Exception($"Invalid build parameter type : {buildParameters.GetType().Name}");
}
}
/// <summary>

View File

@@ -28,7 +28,13 @@ namespace UnityEditor.Build.Pipeline.Tasks
#endif
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
#if TUANJIE_1_0_OR_NEWER
buildTasks.Add(new CreateBuiltInShadersBundle(builtInShaderBundleName));
#else
buildTasks.Add(new CreateBuiltInBundle(builtInShaderBundleName));
#endif
buildTasks.Add(new PostDependencyCallback());
// Packing

View File

@@ -8,8 +8,15 @@ namespace YooAsset.Editor
{
public BuildResult Run(BuildParameters buildParameters, bool enableLog)
{
AssetBundleBuilder builder = new AssetBundleBuilder();
return builder.Run(buildParameters, GetDefaultBuildPipeline(), enableLog);
if (buildParameters is ScriptableBuildParameters)
{
AssetBundleBuilder builder = new AssetBundleBuilder();
return builder.Run(buildParameters, GetDefaultBuildPipeline(), enableLog);
}
else
{
throw new Exception($"Invalid build parameter type : {buildParameters.GetType().Name}");
}
}
/// <summary>

View File

@@ -14,6 +14,7 @@ namespace YooAsset.Editor
PackageOutputDirectoryExists = 115,
RecommendScriptBuildPipeline = 130,
BuildPipelineNotSupportBuildMode = 140,
BuildPipelineNotSupportSharePackRule = 141,
// TaskGetBuildMap
RemoveInvalidTags = 200,

View File

@@ -3,6 +3,6 @@ namespace YooAsset.Editor
{
public interface IBuildPipeline
{
public BuildResult Run(BuildParameters buildParameters, bool enableLog);
BuildResult Run(BuildParameters buildParameters, bool enableLog);
}
}

View File

@@ -65,6 +65,8 @@ namespace YooAsset.Editor
var buildMode = AssetBundleBuilderSetting.GetPackageBuildMode(PackageName, BuildPipeline);
var buildModeList = GetSupportBuildModes();
int defaultIndex = buildModeList.FindIndex(x => x.Equals(buildMode));
if (defaultIndex < 0)
defaultIndex = (int)(EBuildMode)buildModeList[0];
_buildModeField = new PopupField<Enum>(buildModeList, defaultIndex);
_buildModeField.label = "Build Mode";
_buildModeField.style.width = StyleWidth;
@@ -83,6 +85,8 @@ namespace YooAsset.Editor
{
var encyptionClassName = AssetBundleBuilderSetting.GetPackageEncyptionClassName(PackageName, BuildPipeline);
int defaultIndex = encryptionClassTypes.FindIndex(x => x.FullName.Equals(encyptionClassName));
if (defaultIndex < 0)
defaultIndex = 0;
_encryptionField = new PopupField<Type>(encryptionClassTypes, defaultIndex);
_encryptionField.label = "Encryption";
_encryptionField.style.width = StyleWidth;

View File

@@ -1,4 +1,4 @@
#if UNITY_2019_4_OR_NEWER
#if UNITY_2019_4_OR_NEWER
using System;
using System.IO;
using System.Linq;
@@ -18,7 +18,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// ִ<EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>
/// 执行构建
/// </summary>
protected override void ExecuteBuild()
{
@@ -36,6 +36,7 @@ namespace YooAsset.Editor
buildParameters.BuildMode = buildMode;
buildParameters.PackageName = PackageName;
buildParameters.PackageVersion = GetPackageVersion();
buildParameters.EnableSharePackRule = true;
buildParameters.VerifyBuildingResult = true;
buildParameters.FileNameStyle = fileNameStyle;
buildParameters.BuildinFileCopyOption = buildinFileCopyOption;

View File

@@ -1,4 +1,4 @@
#if UNITY_2019_4_OR_NEWER
#if UNITY_2019_4_OR_NEWER
using System;
using System.IO;
using System.Linq;
@@ -20,7 +20,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// ִ<EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>
/// 执行构建
/// </summary>
protected override void ExecuteBuild()
{

View File

@@ -36,6 +36,7 @@ namespace YooAsset.Editor
buildParameters.BuildMode = buildMode;
buildParameters.PackageName = PackageName;
buildParameters.PackageVersion = GetPackageVersion();
buildParameters.EnableSharePackRule = true;
buildParameters.VerifyBuildingResult = true;
buildParameters.FileNameStyle = fileNameStyle;
buildParameters.BuildinFileCopyOption = buildinFileCopyOption;

View File

@@ -166,7 +166,7 @@ namespace YooAsset.Editor
foreach (string assetPath in findAssets)
{
var assetInfo = new AssetInfo(assetPath);
if (IsValidateAsset(command, assetInfo) && IsCollectAsset(group, assetInfo))
if (command.IgnoreRule.IsIgnore(assetInfo) == false && IsCollectAsset(group, assetInfo))
{
if (result.ContainsKey(assetPath) == false)
{
@@ -228,37 +228,6 @@ namespace YooAsset.Editor
return collectAssetInfo;
}
private bool IsValidateAsset(CollectCommand command, AssetInfo assetInfo)
{
if (assetInfo.AssetPath.StartsWith("Assets/") == false && assetInfo.AssetPath.StartsWith("Packages/") == false)
{
UnityEngine.Debug.LogError($"Invalid asset path : {assetInfo.AssetPath}");
return false;
}
// 忽略文件夹
if (AssetDatabase.IsValidFolder(assetInfo.AssetPath))
return false;
// 忽略编辑器下的类型资源
if (assetInfo.AssetType == typeof(LightingDataAsset))
return false;
// 忽略Unity引擎无法识别的文件
if (command.IgnoreDefaultType)
{
if (assetInfo.AssetType == typeof(UnityEditor.DefaultAsset))
{
UnityEngine.Debug.LogWarning($"Cannot pack default asset : {assetInfo.AssetPath}");
return false;
}
}
if (DefaultFilterRule.IsIgnoreFile(assetInfo.FileExtension))
return false;
return true;
}
private bool IsCollectAsset(AssetBundleCollectorGroup group, AssetInfo assetInfo)
{
// 根据规则设置过滤资源文件
@@ -312,7 +281,7 @@ namespace YooAsset.Editor
continue;
AssetInfo assetInfo = new AssetInfo(assetPath);
if (IsValidateAsset(command, assetInfo))
if (command.IgnoreRule.IsIgnore(assetInfo) == false)
result.Add(assetInfo);
}
return result;

View File

@@ -10,7 +10,7 @@ namespace YooAsset.Editor
{
public class AssetBundleCollectorConfig
{
public const string ConfigVersion = "v2.0.0";
public const string ConfigVersion = "v2.1";
public const string XmlVersion = "Version";
public const string XmlCommon = "Common";
@@ -25,7 +25,7 @@ namespace YooAsset.Editor
public const string XmlEnableAddressable = "AutoAddressable";
public const string XmlLocationToLower = "LocationToLower";
public const string XmlIncludeAssetGUID = "IncludeAssetGUID";
public const string XmlIgnoreDefaultType = "IgnoreDefaultType";
public const string XmlIgnoreRuleName = "IgnoreRuleName";
public const string XmlGroup = "Group";
public const string XmlGroupActiveRule = "GroupActiveRule";
@@ -101,7 +101,7 @@ namespace YooAsset.Editor
package.EnableAddressable = packageElement.GetAttribute(XmlEnableAddressable) == "True" ? true : false;
package.LocationToLower = packageElement.GetAttribute(XmlLocationToLower) == "True" ? true : false;
package.IncludeAssetGUID = packageElement.GetAttribute(XmlIncludeAssetGUID) == "True" ? true : false;
package.IgnoreDefaultType = packageElement.GetAttribute(XmlIgnoreDefaultType) == "True" ? true : false;
package.IgnoreRuleName = packageElement.GetAttribute(XmlIgnoreRuleName);
packages.Add(package);
// 读取分组配置
@@ -213,7 +213,7 @@ namespace YooAsset.Editor
packageElement.SetAttribute(XmlEnableAddressable, package.EnableAddressable.ToString());
packageElement.SetAttribute(XmlLocationToLower, package.LocationToLower.ToString());
packageElement.SetAttribute(XmlIncludeAssetGUID, package.IncludeAssetGUID.ToString());
packageElement.SetAttribute(XmlIgnoreDefaultType, package.IgnoreDefaultType.ToString());
packageElement.SetAttribute(XmlIgnoreRuleName, package.IgnoreRuleName);
root.AppendChild(packageElement);
// 设置分组配置
@@ -258,6 +258,23 @@ namespace YooAsset.Editor
if (configVersion == ConfigVersion)
return true;
// v2.0.0 -> v2.1
if (configVersion == "v2.0.0")
{
// 读取包裹配置
var packageNodeList = root.GetElementsByTagName(XmlPackage);
foreach (var packageNode in packageNodeList)
{
XmlElement packageElement = packageNode as XmlElement;
if (packageElement.HasAttribute(XmlIgnoreRuleName) == false)
packageElement.SetAttribute(XmlIgnoreRuleName, nameof(NormalIgnoreRule));
}
// 更新版本
root.SetAttribute(XmlVersion, "v2.1");
return UpdateXmlConfig(xmlDoc);
}
return false;
}
}

View File

@@ -35,16 +35,16 @@ namespace YooAsset.Editor
/// </summary>
public bool IncludeAssetGUID = false;
/// <summary>
/// 忽略Unity引擎无法识别的文件
/// </summary>
public bool IgnoreDefaultType = true;
/// <summary>
/// 自动收集所有着色器(所有着色器存储在一个资源包内)
/// </summary>
public bool AutoCollectShaders = true;
/// <summary>
/// 资源忽略规则名
/// </summary>
public string IgnoreRuleName = nameof(NormalIgnoreRule);
/// <summary>
/// 分组列表
/// </summary>
@@ -56,6 +56,16 @@ namespace YooAsset.Editor
/// </summary>
public void CheckConfigError()
{
if (string.IsNullOrEmpty(IgnoreRuleName))
{
throw new Exception($"{nameof(IgnoreRuleName)} is null or empty !");
}
else
{
if (AssetBundleCollectorSettingData.HasIgnoreRuleName(IgnoreRuleName) == false)
throw new Exception($"Invalid {nameof(IIgnoreRule)} class type : {IgnoreRuleName} in package : {PackageName}");
}
foreach (var group in Groups)
{
group.CheckConfigError();
@@ -68,6 +78,14 @@ namespace YooAsset.Editor
public bool FixConfigError()
{
bool isFixed = false;
if (string.IsNullOrEmpty(IgnoreRuleName))
{
Debug.LogWarning($"Set the {nameof(IgnoreRuleName)} to {nameof(NormalIgnoreRule)}");
IgnoreRuleName = nameof(NormalIgnoreRule);
isFixed = true;
}
foreach (var group in Groups)
{
if (group.FixConfigError())
@@ -75,6 +93,7 @@ namespace YooAsset.Editor
isFixed = true;
}
}
return isFixed;
}

View File

@@ -24,7 +24,6 @@ namespace YooAsset.Editor
/// </summary>
public bool UniqueBundleName = false;
/// <summary>
/// 包裹列表
/// </summary>
@@ -100,13 +99,13 @@ namespace YooAsset.Editor
package.CheckConfigError();
// 创建资源收集命令
IIgnoreRule ignoreRule = AssetBundleCollectorSettingData.GetIgnoreRuleInstance(package.IgnoreRuleName);
CollectCommand command = new CollectCommand(buildMode, packageName,
package.EnableAddressable,
package.LocationToLower,
package.IncludeAssetGUID,
package.IgnoreDefaultType,
package.AutoCollectShaders,
UniqueBundleName);
UniqueBundleName, ignoreRule);
// 获取收集的资源集合
CollectResult collectResult = new CollectResult(command);

View File

@@ -21,6 +21,9 @@ namespace YooAsset.Editor
private static readonly Dictionary<string, System.Type> _cacheFilterRuleTypes = new Dictionary<string, System.Type>();
private static readonly Dictionary<string, IFilterRule> _cacheFilterRuleInstance = new Dictionary<string, IFilterRule>();
private static readonly Dictionary<string, System.Type> _cacheIgnoreRuleTypes = new Dictionary<string, System.Type>();
private static readonly Dictionary<string, IIgnoreRule> _cacheIgnoreRuleInstance = new Dictionary<string, IIgnoreRule>();
/// <summary>
/// 配置数据是否被修改
/// </summary>
@@ -129,6 +132,29 @@ namespace YooAsset.Editor
_cacheActiveRuleTypes.Add(type.Name, type);
}
}
// IIgnoreRule
{
// 清空缓存集合
_cacheIgnoreRuleTypes.Clear();
_cacheIgnoreRuleInstance.Clear();
// 获取所有类型
List<Type> types = new List<Type>(100)
{
typeof(NormalIgnoreRule),
typeof(RawFileIgnoreRule),
};
var customTypes = EditorTools.GetAssignableTypes(typeof(IIgnoreRule));
types.AddRange(customTypes);
for (int i = 0; i < types.Count; i++)
{
Type type = types[i];
if (_cacheIgnoreRuleTypes.ContainsKey(type.Name) == false)
_cacheIgnoreRuleTypes.Add(type.Name, type);
}
}
}
private static AssetBundleCollectorSetting _setting = null;
@@ -165,6 +191,7 @@ namespace YooAsset.Editor
if (isFixed)
{
IsDirty = true;
Debug.Log("Fix package config error done !");
}
}
@@ -225,6 +252,18 @@ namespace YooAsset.Editor
}
return names;
}
public static List<RuleDisplayName> GetIgnoreRuleNames()
{
List<RuleDisplayName> names = new List<RuleDisplayName>();
foreach (var pair in _cacheIgnoreRuleTypes)
{
RuleDisplayName ruleName = new RuleDisplayName();
ruleName.ClassName = pair.Key;
ruleName.DisplayName = GetRuleDisplayName(pair.Key, pair.Value);
names.Add(ruleName);
}
return names;
}
private static string GetRuleDisplayName(string name, Type type)
{
var attribute = DisplayNameAttributeHelper.GetAttribute<DisplayNameAttribute>(type);
@@ -236,19 +275,23 @@ namespace YooAsset.Editor
public static bool HasActiveRuleName(string ruleName)
{
return _cacheActiveRuleTypes.Keys.Contains(ruleName);
return _cacheActiveRuleTypes.ContainsKey(ruleName);
}
public static bool HasAddressRuleName(string ruleName)
{
return _cacheAddressRuleTypes.Keys.Contains(ruleName);
return _cacheAddressRuleTypes.ContainsKey(ruleName);
}
public static bool HasPackRuleName(string ruleName)
{
return _cachePackRuleTypes.Keys.Contains(ruleName);
return _cachePackRuleTypes.ContainsKey(ruleName);
}
public static bool HasFilterRuleName(string ruleName)
{
return _cacheFilterRuleTypes.Keys.Contains(ruleName);
return _cacheFilterRuleTypes.ContainsKey(ruleName);
}
public static bool HasIgnoreRuleName(string ruleName)
{
return _cacheIgnoreRuleTypes.ContainsKey(ruleName);
}
public static IActiveRule GetActiveRuleInstance(string ruleName)
@@ -319,6 +362,23 @@ namespace YooAsset.Editor
throw new Exception($"{nameof(IFilterRule)} is invalid{ruleName}");
}
}
public static IIgnoreRule GetIgnoreRuleInstance(string ruleName)
{
if (_cacheIgnoreRuleInstance.TryGetValue(ruleName, out IIgnoreRule instance))
return instance;
// 如果不存在创建类的实例
if (_cacheIgnoreRuleTypes.TryGetValue(ruleName, out Type type))
{
instance = (IIgnoreRule)Activator.CreateInstance(type);
_cacheIgnoreRuleInstance.Add(ruleName, instance);
return instance;
}
else
{
throw new Exception($"{nameof(IIgnoreRule)} is invalid{ruleName}");
}
}
// 公共参数编辑相关
public static void ModifyShowPackageView(bool showPackageView)

View File

@@ -24,6 +24,7 @@ namespace YooAsset.Editor
private List<RuleDisplayName> _addressRuleList;
private List<RuleDisplayName> _packRuleList;
private List<RuleDisplayName> _filterRuleList;
private List<RuleDisplayName> _ignoreRuleList;
private VisualElement _helpBoxContainer;
@@ -39,9 +40,9 @@ namespace YooAsset.Editor
private Toggle _enableAddressableToogle;
private Toggle _locationToLowerToogle;
private Toggle _includeAssetGUIDToogle;
private Toggle _ignoreDefaultTypeToogle;
private Toggle _autoCollectShadersToogle;
private PopupField<RuleDisplayName> _ignoreRulePopupField;
private VisualElement _packageContainer;
private ListView _packageListView;
private TextField _packageNameTxt;
@@ -77,6 +78,7 @@ namespace YooAsset.Editor
_addressRuleList = AssetBundleCollectorSettingData.GetAddressRuleNames();
_packRuleList = AssetBundleCollectorSettingData.GetPackRuleNames();
_filterRuleList = AssetBundleCollectorSettingData.GetFilterRuleNames();
_ignoreRuleList = AssetBundleCollectorSettingData.GetIgnoreRuleNames();
VisualElement root = this.rootVisualElement;
@@ -151,17 +153,6 @@ namespace YooAsset.Editor
RefreshWindow();
}
});
_ignoreDefaultTypeToogle = root.Q<Toggle>("IgnoreDefaultType");
_ignoreDefaultTypeToogle.RegisterValueChangedCallback(evt =>
{
var selectPackage = _packageListView.selectedItem as AssetBundleCollectorPackage;
if (selectPackage != null)
{
selectPackage.IgnoreDefaultType = evt.newValue;
AssetBundleCollectorSettingData.ModifyPackage(selectPackage);
RefreshWindow();
}
});
_autoCollectShadersToogle = root.Q<Toggle>("AutoCollectShaders");
_autoCollectShadersToogle.RegisterValueChangedCallback(evt =>
{
@@ -173,6 +164,25 @@ namespace YooAsset.Editor
RefreshWindow();
}
});
{
_ignoreRulePopupField = new PopupField<RuleDisplayName>(_ignoreRuleList, 0);
_ignoreRulePopupField.label = "File Ignore Rule";
_ignoreRulePopupField.name = "IgnoreRulePopupField";
_ignoreRulePopupField.style.unityTextAlign = TextAnchor.MiddleLeft;
_ignoreRulePopupField.style.width = 300;
_ignoreRulePopupField.formatListItemCallback = FormatListItemCallback;
_ignoreRulePopupField.formatSelectedValueCallback = FormatSelectedValueCallback;
_ignoreRulePopupField.RegisterValueChangedCallback(evt =>
{
var selectPackage = _packageListView.selectedItem as AssetBundleCollectorPackage;
if(selectPackage != null)
{
selectPackage.IgnoreRuleName = evt.newValue.ClassName;
AssetBundleCollectorSettingData.ModifyPackage(selectPackage);
}
});
_setting2Container.Add(_ignoreRulePopupField);
}
// 配置修复按钮
var fixBtn = root.Q<Button>("FixButton");
@@ -475,7 +485,8 @@ namespace YooAsset.Editor
_enableAddressableToogle.SetValueWithoutNotify(selectPackage.EnableAddressable);
_locationToLowerToogle.SetValueWithoutNotify(selectPackage.LocationToLower);
_includeAssetGUIDToogle.SetValueWithoutNotify(selectPackage.IncludeAssetGUID);
_ignoreDefaultTypeToogle.SetValueWithoutNotify(selectPackage.IgnoreDefaultType);
_autoCollectShadersToogle.SetValueWithoutNotify(selectPackage.AutoCollectShaders);
_ignoreRulePopupField.SetValueWithoutNotify(GetIgnoreRuleIndex(selectPackage.IgnoreRuleName));
}
else
{
@@ -969,7 +980,7 @@ namespace YooAsset.Editor
if (collector.IsValid() == false)
{
Debug.LogWarning($"The collector is invalid : {collector.CollectPath} in group : {group.GroupName}");
collector.CheckConfigError();
return;
}
@@ -979,14 +990,15 @@ namespace YooAsset.Editor
try
{
IIgnoreRule ignoreRule = AssetBundleCollectorSettingData.GetIgnoreRuleInstance(_ignoreRulePopupField.value.ClassName);
CollectCommand command = new CollectCommand(EBuildMode.SimulateBuild,
_packageNameTxt.value,
_enableAddressableToogle.value,
_locationToLowerToogle.value,
_includeAssetGUIDToogle.value,
_ignoreDefaultTypeToogle.value,
_autoCollectShadersToogle.value,
_uniqueBundleNameToogle.value);
_uniqueBundleNameToogle.value,
ignoreRule);
collector.CheckConfigError();
collectAssetInfos = collector.GetAllCollectAssets(command, group);
}
@@ -1077,6 +1089,15 @@ namespace YooAsset.Editor
}
return 0;
}
private RuleDisplayName GetIgnoreRuleIndex(string ruleName)
{
for (int i = 0; i < _ignoreRuleList.Count; i++)
{
if (_ignoreRuleList[i].ClassName == ruleName)
return _ignoreRuleList[i];
}
return _ignoreRuleList[0];
}
private RuleDisplayName GetActiveRuleIndex(string ruleName)
{
for (int i = 0; i < _activeRuleList.Count; i++)

View File

@@ -21,7 +21,6 @@
<ui:Toggle label="Enable Addressable" name="EnableAddressable" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Location To Lower" name="LocationToLower" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Include Asset GUID" name="IncludeAssetGUID" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Ignore Default Type" name="IgnoreDefaultType" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Auto Collect Shaders" name="AutoCollectShaders" value="true" style="width: 196px; -unity-text-align: middle-left;" />
</ui:VisualElement>
</ui:VisualElement>

View File

@@ -13,11 +13,6 @@ namespace YooAsset.Editor
/// </summary>
public string PackageName { private set; get; }
/// <summary>
/// 忽略Unity引擎无法识别的文件
/// </summary>
public bool IgnoreDefaultType { private set; get; }
/// <summary>
/// 启用可寻址资源定位
/// </summary>
@@ -48,17 +43,24 @@ namespace YooAsset.Editor
/// </summary>
public string ShadersBundleName { private set; get; }
/// <summary>
/// 忽略规则实例
/// </summary>
public IIgnoreRule IgnoreRule { private set; get; }
public CollectCommand(EBuildMode buildMode, string packageName, bool enableAddressable, bool locationToLower, bool includeAssetGUID, bool ignoreDefaultType, bool autoCollectShaders, bool uniqueBundleName)
public CollectCommand(EBuildMode buildMode, string packageName,
bool enableAddressable, bool locationToLower, bool includeAssetGUID,
bool autoCollectShaders, bool uniqueBundleName, IIgnoreRule ignoreRule)
{
BuildMode = buildMode;
PackageName = packageName;
EnableAddressable = enableAddressable;
LocationToLower = locationToLower;
IncludeAssetGUID = includeAssetGUID;
IgnoreDefaultType = ignoreDefaultType;
AutoCollectShaders = autoCollectShaders;
UniqueBundleName = uniqueBundleName;
IgnoreRule = ignoreRule;
// 着色器统一全名称
var packRuleResult = DefaultPackRule.CreateShadersPackRuleResult();

View File

@@ -0,0 +1,11 @@

namespace YooAsset.Editor
{
/// <summary>
/// 资源忽略规则接口
/// </summary>
public interface IIgnoreRule
{
bool IsIgnore(AssetInfo assetInfo);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 02ad351eb8539da47a0c789e2f8c468f
guid: bd55753dbb880fa449bf4e37b33d8ba7
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -28,19 +28,41 @@ namespace YooAsset.Editor
_bundleExtension = bundleExtension;
}
/// <summary>
/// 结果是否有效
/// </summary>
public bool IsValid()
{
return string.IsNullOrEmpty(_bundleName) == false && string.IsNullOrEmpty(_bundleExtension) == false;
}
/// <summary>
/// 获取资源包全名称
/// </summary>
public string GetBundleName(string packageName, bool uniqueBundleName)
{
string fullName;
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').ToLower();
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').Replace(" ", "_").ToLower();
if (uniqueBundleName)
fullName = $"{packageName}_{bundleName}.{_bundleExtension}";
else
fullName = $"{bundleName}.{_bundleExtension}";
return fullName.ToLower();
}
/// <summary>
/// 获取共享资源包全名称
/// </summary>
public string GetShareBundleName(string packageName, bool uniqueBundleName)
{
string fullName;
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').Replace(" ", "_").ToLower();
if (uniqueBundleName)
fullName = $"{packageName}_share_{bundleName}.{_bundleExtension}";
else
fullName = $"share_{bundleName}.{_bundleExtension}";
return fullName.ToLower();
}
}
/// <summary>

View File

@@ -6,22 +6,6 @@ using UnityEditor;
namespace YooAsset.Editor
{
public class DefaultFilterRule
{
/// <summary>
/// 忽略的文件类型
/// </summary>
private readonly static HashSet<string> _ignoreFileExtensions = new HashSet<string>() { "", ".so", ".dll", ".cs", ".js", ".boo", ".meta", ".cginc", ".hlsl" };
/// <summary>
/// 查询是否为忽略文件
/// </summary>
public static bool IsIgnoreFile(string fileExtension)
{
return _ignoreFileExtensions.Contains(fileExtension);
}
}
[DisplayName("收集所有资源")]
public class CollectAll : IFilterRule
{
@@ -36,7 +20,8 @@ namespace YooAsset.Editor
{
public bool IsCollectAsset(FilterRuleData data)
{
return Path.GetExtension(data.AssetPath) == ".unity";
string extension = Path.GetExtension(data.AssetPath);
return extension == ".unity" || extension == ".scene";
}
}
@@ -70,6 +55,15 @@ namespace YooAsset.Editor
}
}
[DisplayName("收集着色器")]
public class CollectShader : IFilterRule
{
public bool IsCollectAsset(FilterRuleData data)
{
return Path.GetExtension(data.AssetPath) == ".shader";
}
}
[DisplayName("收集着色器变种集合")]
public class CollectShaderVariants : IFilterRule
{

View File

@@ -0,0 +1,82 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace YooAsset.Editor
{
public class DefaultIgnoreRule
{
/// <summary>
/// 忽略的文件类型
/// </summary>
public readonly static HashSet<string> IgnoreFileExtensions = new HashSet<string>() { "", ".so", ".dll", ".cs", ".js", ".boo", ".meta", ".cginc", ".hlsl" };
}
/// <summary>
/// 适配常规的资源构建管线
/// </summary>
public class NormalIgnoreRule : IIgnoreRule
{
/// <summary>
/// 查询是否为忽略文件
/// </summary>
public bool IsIgnore(AssetInfo assetInfo)
{
if (assetInfo.AssetPath.StartsWith("Assets/") == false && assetInfo.AssetPath.StartsWith("Packages/") == false)
{
UnityEngine.Debug.LogError($"Invalid asset path : {assetInfo.AssetPath}");
return true;
}
// 忽略文件夹
if (AssetDatabase.IsValidFolder(assetInfo.AssetPath))
return true;
// 忽略编辑器下的类型资源
if (assetInfo.AssetType == typeof(LightingDataAsset))
return true;
if (assetInfo.AssetType == typeof(LightmapParameters))
return true;
// 忽略Unity引擎无法识别的文件
if (assetInfo.AssetType == typeof(UnityEditor.DefaultAsset))
{
UnityEngine.Debug.LogWarning($"Cannot pack default asset : {assetInfo.AssetPath}");
return true;
}
return DefaultIgnoreRule.IgnoreFileExtensions.Contains(assetInfo.FileExtension);
}
}
/// <summary>
/// 适配原生文件构建管线
/// </summary>
public class RawFileIgnoreRule : IIgnoreRule
{
/// <summary>
/// 查询是否为忽略文件
/// </summary>
public bool IsIgnore(AssetInfo assetInfo)
{
if (assetInfo.AssetPath.StartsWith("Assets/") == false && assetInfo.AssetPath.StartsWith("Packages/") == false)
{
UnityEngine.Debug.LogError($"Invalid asset path : {assetInfo.AssetPath}");
return true;
}
// 忽略文件夹
if (AssetDatabase.IsValidFolder(assetInfo.AssetPath))
return true;
// 忽略编辑器下的类型资源
if (assetInfo.AssetType == typeof(LightingDataAsset))
return true;
if (assetInfo.AssetType == typeof(LightmapParameters))
return true;
return DefaultIgnoreRule.IgnoreFileExtensions.Contains(assetInfo.FileExtension);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8616c7550a7890141af598898a12df1b
guid: b9c1900577194bb4ab49ce4332ccc4bc
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -147,6 +147,18 @@ namespace YooAsset.Editor
}
}
/// <summary>
/// 打包着色器
/// </summary>
[DisplayName("打包着色器文件")]
public class PackShader : IPackRule
{
public PackRuleResult GetPackRuleResult(PackRuleData data)
{
return DefaultPackRule.CreateShadersPackRuleResult();
}
}
/// <summary>
/// 打包着色器变种集合
/// </summary>

View File

@@ -189,7 +189,7 @@ namespace YooAsset.Editor
// Status
StyleColor textColor;
if (bundleInfo.Status == BundleLoaderBase.EStatus.Failed.ToString())
if (bundleInfo.Status == EOperationStatus.Failed)
textColor = new StyleColor(Color.yellow);
else
textColor = label1.style.color;

View File

@@ -58,10 +58,11 @@ namespace YooAsset.Editor
public bool EnableAddressable;
public bool LocationToLower;
public bool IncludeAssetGUID;
public bool IgnoreDefaultType;
public bool AutoCollectShaders;
public string IgnoreRuleName;
// 构建参数
public bool EnableSharePackRule;
public string EncryptionClassName;
public EFileNameStyle FileNameStyle;
public ECompressOption CompressOption;

View File

@@ -67,16 +67,17 @@ namespace YooAsset.Editor
_items.Add(new ItemWrapper("Package Version", buildReport.Summary.BuildPackageVersion));
_items.Add(new ItemWrapper(string.Empty, string.Empty));
_items.Add(new ItemWrapper("Settings", string.Empty));
_items.Add(new ItemWrapper("Collect Settings", string.Empty));
_items.Add(new ItemWrapper("Unique Bundle Name", $"{buildReport.Summary.UniqueBundleName}"));
_items.Add(new ItemWrapper("Enable Addressable", $"{buildReport.Summary.EnableAddressable}"));
_items.Add(new ItemWrapper("Location To Lower", $"{buildReport.Summary.LocationToLower}"));
_items.Add(new ItemWrapper("Include Asset GUID", $"{buildReport.Summary.IncludeAssetGUID}"));
_items.Add(new ItemWrapper("Ignore Default Type", $"{buildReport.Summary.IgnoreDefaultType}"));
_items.Add(new ItemWrapper("Auto Collect Shaders", $"{buildReport.Summary.AutoCollectShaders}"));
_items.Add(new ItemWrapper("Ignore Rule Name", $"{buildReport.Summary.IgnoreRuleName}"));
_items.Add(new ItemWrapper(string.Empty, string.Empty));
_items.Add(new ItemWrapper("Build Params", string.Empty));
_items.Add(new ItemWrapper("Enable Share Pack Rule", $"{buildReport.Summary.EnableSharePackRule}"));
_items.Add(new ItemWrapper("Encryption Class Name", buildReport.Summary.EncryptionClassName));
_items.Add(new ItemWrapper("FileNameStyle", $"{buildReport.Summary.FileNameStyle}"));
_items.Add(new ItemWrapper("CompressOption", $"{buildReport.Summary.CompressOption}"));

View File

@@ -496,14 +496,6 @@ namespace YooAsset.Editor
return fileInfo.Length;
}
/// <summary>
/// 获取文件的哈希值
/// </summary>
public static string GetFileCRC32(string filePath)
{
return HashUtility.FileCRC32(filePath);
}
/// <summary>
/// 读取文件的所有文本内容
/// </summary>
@@ -567,6 +559,21 @@ namespace YooAsset.Editor
{
return path.Replace('\\', '/').Replace("\\", "/"); //替换为Linux路径格式
}
/// <summary>
/// 移除路径里的后缀名
/// </summary>
public static string RemoveExtension(string str)
{
if (string.IsNullOrEmpty(str))
return str;
int index = str.LastIndexOf('.');
if (index == -1)
return str;
else
return str.Remove(index); //"assets/config/test.unity3d" --> "assets/config/test"
}
/// <summary>
/// 获取项目工程路径

View File

@@ -1,36 +0,0 @@
using System;
using System.IO;
namespace YooAsset
{
internal class CacheFileInfo
{
private static readonly BufferWriter SharedBuffer = new BufferWriter(1024);
/// <summary>
/// 写入资源包信息
/// </summary>
public static void WriteInfoToFile(string filePath, string dataFileCRC, long dataFileSize)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
SharedBuffer.Clear();
SharedBuffer.WriteUTF8(dataFileCRC);
SharedBuffer.WriteInt64(dataFileSize);
SharedBuffer.WriteToStream(fs);
fs.Flush();
}
}
/// <summary>
/// 读取资源包信息
/// </summary>
public static void ReadInfoFromFile(string filePath, out string dataFileCRC, out long dataFileSize)
{
byte[] binaryData = FileUtility.ReadAllBytes(filePath);
BufferReader buffer = new BufferReader(binaryData);
dataFileCRC = buffer.ReadUTF8();
dataFileSize = buffer.ReadInt64();
}
}
}

View File

@@ -1,103 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace YooAsset
{
internal static class CacheHelper
{
/// <summary>
/// 禁用Unity缓存系统在WebGL平台
/// </summary>
public static bool DisableUnityCacheOnWebGL = false;
/// <summary>
/// 验证缓存文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingCacheFile(VerifyCacheFileElement element, EVerifyLevel verifyLevel)
{
try
{
if (verifyLevel == EVerifyLevel.Low)
{
if (File.Exists(element.InfoFilePath) == false)
return EVerifyResult.InfoFileNotExisted;
if (File.Exists(element.DataFilePath) == false)
return EVerifyResult.DataFileNotExisted;
return EVerifyResult.Succeed;
}
else
{
if (File.Exists(element.InfoFilePath) == false)
return EVerifyResult.InfoFileNotExisted;
// 解析信息文件获取验证数据
CacheFileInfo.ReadInfoFromFile(element.InfoFilePath, out element.DataFileCRC, out element.DataFileSize);
}
}
catch (Exception)
{
return EVerifyResult.Exception;
}
return VerifyingInternal(element.DataFilePath, element.DataFileSize, element.DataFileCRC, verifyLevel);
}
/// <summary>
/// 验证下载文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingTempFile(VerifyTempFileElement element)
{
return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High);
}
/// <summary>
/// 验证记录文件(主线程内操作)
/// </summary>
public static EVerifyResult VerifyingRecordFile(CacheManager cache, string cacheGUID)
{
var wrapper = cache.TryGetWrapper(cacheGUID);
if (wrapper == null)
return EVerifyResult.CacheNotFound;
EVerifyResult result = VerifyingInternal(wrapper.DataFilePath, wrapper.DataFileSize, wrapper.DataFileCRC, EVerifyLevel.High);
return result;
}
private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
{
try
{
if (File.Exists(filePath) == false)
return EVerifyResult.DataFileNotExisted;
// 先验证文件大小
long size = FileUtility.GetFileSize(filePath);
if (size < fileSize)
return EVerifyResult.FileNotComplete;
else if (size > fileSize)
return EVerifyResult.FileOverflow;
// 再验证文件CRC
if (verifyLevel == EVerifyLevel.High)
{
string crc = HashUtility.FileCRC32(filePath);
if (crc == fileCRC)
return EVerifyResult.Succeed;
else
return EVerifyResult.FileCrcError;
}
else
{
return EVerifyResult.Succeed;
}
}
catch (Exception)
{
return EVerifyResult.Exception;
}
}
}
}

View File

@@ -1,136 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class CacheManager
{
internal class RecordWrapper
{
public string InfoFilePath { private set; get; }
public string DataFilePath { private set; get; }
public string DataFileCRC { private set; get; }
public long DataFileSize { private set; get; }
public RecordWrapper(string infoFilePath, string dataFilePath, string dataFileCRC, long dataFileSize)
{
InfoFilePath = infoFilePath;
DataFilePath = dataFilePath;
DataFileCRC = dataFileCRC;
DataFileSize = dataFileSize;
}
}
private readonly Dictionary<string, RecordWrapper> _wrappers = new Dictionary<string, RecordWrapper>();
/// <summary>
/// 所属包裹
/// </summary>
public readonly string PackageName;
/// <summary>
/// 验证级别
/// </summary>
public readonly EVerifyLevel BootVerifyLevel;
public CacheManager(string packageName, EVerifyLevel bootVerifyLevel)
{
PackageName = packageName;
BootVerifyLevel = bootVerifyLevel;
}
/// <summary>
/// 清空所有数据
/// </summary>
public void ClearAll()
{
_wrappers.Clear();
}
/// <summary>
/// 查询缓存记录
/// </summary>
public bool IsCached(string cacheGUID)
{
return _wrappers.ContainsKey(cacheGUID);
}
/// <summary>
/// 记录验证结果
/// </summary>
public void Record(string cacheGUID, RecordWrapper wrapper)
{
if (_wrappers.ContainsKey(cacheGUID) == false)
{
_wrappers.Add(cacheGUID, wrapper);
}
else
{
throw new Exception("Should never get here !");
}
}
/// <summary>
/// 丢弃验证结果并删除缓存文件
/// </summary>
public void Discard(string cacheGUID)
{
var wrapper = TryGetWrapper(cacheGUID);
if (wrapper != null)
{
try
{
string dataFilePath = wrapper.DataFilePath;
FileInfo fileInfo = new FileInfo(dataFilePath);
if (fileInfo.Exists)
fileInfo.Directory.Delete(true);
}
catch (Exception e)
{
YooLogger.Error($"Failed to delete cache file ! {e.Message}");
}
}
if (_wrappers.ContainsKey(cacheGUID))
{
_wrappers.Remove(cacheGUID);
}
}
/// <summary>
/// 获取记录对象
/// </summary>
public RecordWrapper TryGetWrapper(string cacheGUID)
{
if (_wrappers.TryGetValue(cacheGUID, out RecordWrapper value))
return value;
else
return null;
}
/// <summary>
/// 获取缓存文件总数
/// </summary>
public int GetAllCachedFilesCount()
{
return _wrappers.Count;
}
/// <summary>
/// 获取缓存GUID集合
/// </summary>
public List<string> GetAllCachedGUIDs()
{
List<string> keys = new List<string>(_wrappers.Keys.Count);
var keyCollection = _wrappers.Keys;
foreach (var key in keyCollection)
{
keys.Add(key);
}
return keys;
}
}
}

View File

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

View File

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

View File

@@ -1,87 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 清理本地包裹未使用的缓存文件
/// </summary>
public sealed class ClearUnusedCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
{
None,
GetUnusedCacheFiles,
ClearUnusedCacheFiles,
Done,
}
private readonly ResourcePackage _package;
private readonly CacheManager _cache;
private List<string> _unusedCacheGUIDs;
private int _unusedFileTotalCount = 0;
private ESteps _steps = ESteps.None;
internal ClearUnusedCacheFilesOperation(ResourcePackage package, CacheManager cache)
{
_package = package;
_cache = cache;
}
internal override void InternalOnStart()
{
_steps = ESteps.GetUnusedCacheFiles;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetUnusedCacheFiles)
{
_unusedCacheGUIDs = GetUnusedCacheGUIDs();
_unusedFileTotalCount = _unusedCacheGUIDs.Count;
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
_steps = ESteps.ClearUnusedCacheFiles;
}
if (_steps == ESteps.ClearUnusedCacheFiles)
{
for (int i = _unusedCacheGUIDs.Count - 1; i >= 0; i--)
{
string cacheGUID = _unusedCacheGUIDs[i];
_cache.Discard(cacheGUID);
_unusedCacheGUIDs.RemoveAt(i);
if (OperationSystem.IsBusy)
break;
}
if (_unusedFileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - (_unusedCacheGUIDs.Count / _unusedFileTotalCount);
if (_unusedCacheGUIDs.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
private List<string> GetUnusedCacheGUIDs()
{
var allCacheGUIDs = _cache.GetAllCachedGUIDs();
List<string> result = new List<string>(allCacheGUIDs.Count);
foreach (var cacheGUID in allCacheGUIDs)
{
if (_package.IsIncludeBundleFile(cacheGUID) == false)
{
result.Add(cacheGUID);
}
}
return result;
}
}
}

View File

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

View File

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

View File

@@ -1,254 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
internal abstract class VerifyCacheFilesOperation : AsyncOperationBase
{
public static VerifyCacheFilesOperation CreateOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
{
#if UNITY_WEBGL
var operation = new VerifyCacheFilesWithoutThreadOperation(cache, elements);
#else
var operation = new VerifyCacheFilesWithThreadOperation(cache, elements);
#endif
return operation;
}
}
/// <summary>
/// 本地缓存文件验证(线程版)
/// </summary>
internal class VerifyCacheFilesWithThreadOperation : VerifyCacheFilesOperation
{
private enum ESteps
{
None,
InitVerify,
UpdateVerify,
Done,
}
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private readonly CacheManager _cache;
private List<VerifyCacheFileElement> _waitingList;
private List<VerifyCacheFileElement> _verifyingList;
private int _verifyMaxNum;
private int _verifyTotalCount;
private float _verifyStartTime;
private int _succeedCount;
private int _failedCount;
private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithThreadOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
{
_cache = cache;
_waitingList = elements;
}
internal override void InternalOnStart()
{
_steps = ESteps.InitVerify;
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.InitVerify)
{
int fileCount = _waitingList.Count;
// 设置同时验证的最大数
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
_verifyTotalCount = fileCount;
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
_verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify;
}
if (_steps == ESteps.UpdateVerify)
{
_syncContext.Update();
Progress = GetProgress();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
}
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (OperationSystem.IsBusy)
break;
if (_verifyingList.Count >= _verifyMaxNum)
break;
var element = _waitingList[i];
if (BeginVerifyFileWithThread(element))
{
_waitingList.RemoveAt(i);
_verifyingList.Add(element);
}
else
{
YooLogger.Warning("The thread pool is failed queued.");
break;
}
}
}
}
private float GetProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
}
private bool BeginVerifyFileWithThread(VerifyCacheFileElement element)
{
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
}
private void VerifyInThread(object obj)
{
VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
element.Result = CacheHelper.VerifyingCacheFile(element, _cache.BootVerifyLevel);
_syncContext.Post(VerifyCallback, element);
}
private void VerifyCallback(object obj)
{
VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
_verifyingList.Remove(element);
if (element.Result == EVerifyResult.Succeed)
{
_succeedCount++;
var wrapper = new CacheManager.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
_cache.Record(element.CacheGUID, wrapper);
}
else
{
_failedCount++;
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
element.DeleteFiles();
}
}
}
/// <summary>
/// 本地缓存文件验证(非线程版)
/// </summary>
internal class VerifyCacheFilesWithoutThreadOperation : VerifyCacheFilesOperation
{
private enum ESteps
{
None,
InitVerify,
UpdateVerify,
Done,
}
private readonly CacheManager _cache;
private List<VerifyCacheFileElement> _waitingList;
private List<VerifyCacheFileElement> _verifyingList;
private int _verifyMaxNum;
private int _verifyTotalCount;
private float _verifyStartTime;
private int _succeedCount;
private int _failedCount;
private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithoutThreadOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
{
_cache = cache;
_waitingList = elements;
}
internal override void InternalOnStart()
{
_steps = ESteps.InitVerify;
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.InitVerify)
{
int fileCount = _waitingList.Count;
// 设置同时验证的最大数
_verifyMaxNum = fileCount;
_verifyTotalCount = fileCount;
_verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify;
}
if (_steps == ESteps.UpdateVerify)
{
Progress = GetProgress();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Package verify elapsed time {costTime:f1} seconds");
}
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (OperationSystem.IsBusy)
break;
if (_verifyingList.Count >= _verifyMaxNum)
break;
var element = _waitingList[i];
BeginVerifyFileWithoutThread(element);
_waitingList.RemoveAt(i);
_verifyingList.Add(element);
}
// 主线程内验证,可以清空列表
_verifyingList.Clear();
}
}
private float GetProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
}
private void BeginVerifyFileWithoutThread(VerifyCacheFileElement element)
{
element.Result = CacheHelper.VerifyingCacheFile(element, _cache.BootVerifyLevel);
if (element.Result == EVerifyResult.Succeed)
{
_succeedCount++;
var wrapper = new CacheManager.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
_cache.Record(element.CacheGUID, wrapper);
}
else
{
_failedCount++;
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
element.DeleteFiles();
}
}
}
}

View File

@@ -1,141 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
internal abstract class VerifyTempFileOperation : AsyncOperationBase
{
public EVerifyResult VerifyResult { protected set; get; }
public static VerifyTempFileOperation CreateOperation(VerifyTempFileElement element)
{
#if UNITY_WEBGL
var operation = new VerifyTempFileWithoutThreadOperation(element);
#else
var operation = new VerifyTempFileWithThreadOperation(element);
#endif
return operation;
}
}
/// <summary>
/// 下载文件验证(线程版)
/// </summary>
internal class VerifyTempFileWithThreadOperation : VerifyTempFileOperation
{
private enum ESteps
{
None,
VerifyFile,
Waiting,
Done,
}
private readonly VerifyTempFileElement _element;
private ESteps _steps = ESteps.None;
public VerifyTempFileWithThreadOperation(VerifyTempFileElement element)
{
_element = element;
}
internal override void InternalOnStart()
{
_steps = ESteps.VerifyFile;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.VerifyFile)
{
if (BeginVerifyFileWithThread(_element))
{
_steps = ESteps.Waiting;
}
}
if (_steps == ESteps.Waiting)
{
int result = _element.Result;
if (result == 0)
return;
VerifyResult = (EVerifyResult)result;
if (VerifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
}
}
}
private bool BeginVerifyFileWithThread(VerifyTempFileElement element)
{
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
}
private void VerifyInThread(object obj)
{
VerifyTempFileElement element = (VerifyTempFileElement)obj;
int result = (int)CacheHelper.VerifyingTempFile(element);
element.Result = result;
}
}
/// <summary>
/// 下载文件验证(非线程版)
/// </summary>
internal class VerifyTempFileWithoutThreadOperation : VerifyTempFileOperation
{
private enum ESteps
{
None,
VerifyFile,
Done,
}
private readonly VerifyTempFileElement _element;
private ESteps _steps = ESteps.None;
public VerifyTempFileWithoutThreadOperation(VerifyTempFileElement element)
{
_element = element;
}
internal override void InternalOnStart()
{
_steps = ESteps.VerifyFile;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.VerifyFile)
{
_element.Result = (int)CacheHelper.VerifyingTempFile(_element);
VerifyResult = (EVerifyResult)_element.Result;
if (VerifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
}
}
}
}
}

View File

@@ -1,74 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class PackageCachingOperation : AsyncOperationBase
{
private enum ESteps
{
None,
FindCacheFiles,
VerifyCacheFiles,
Done,
}
private readonly PersistentManager _persistent;
private readonly CacheManager _cache;
private FindCacheFilesOperation _findCacheFilesOp;
private VerifyCacheFilesOperation _verifyCacheFilesOp;
private ESteps _steps = ESteps.None;
public PackageCachingOperation(PersistentManager persistent, CacheManager cache)
{
_persistent = persistent;
_cache = cache;
}
internal override void InternalOnStart()
{
_steps = ESteps.FindCacheFiles;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.FindCacheFiles)
{
if (_findCacheFilesOp == null)
{
_findCacheFilesOp = new FindCacheFilesOperation(_persistent, _cache);
OperationSystem.StartOperation(_cache.PackageName, _findCacheFilesOp);
}
Progress = _findCacheFilesOp.Progress;
if (_findCacheFilesOp.IsDone == false)
return;
_steps = ESteps.VerifyCacheFiles;
}
if (_steps == ESteps.VerifyCacheFiles)
{
if (_verifyCacheFilesOp == null)
{
_verifyCacheFilesOp = VerifyCacheFilesOperation.CreateOperation(_cache, _findCacheFilesOp.VerifyElements);
OperationSystem.StartOperation(_cache.PackageName, _verifyCacheFilesOp);
}
Progress = _verifyCacheFilesOp.Progress;
if (_verifyCacheFilesOp.IsDone == false)
return;
// 注意:总是返回成功
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
int totalCount = _cache.GetAllCachedFilesCount();
YooLogger.Log($"Package '{_cache.PackageName}' cached files count : {totalCount}");
}
}
}
}

View File

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

View File

@@ -1,28 +0,0 @@

namespace YooAsset
{
internal static class PersistentHelper
{
/// <summary>
/// 获取WWW加载本地资源的路径
/// </summary>
public static string ConvertToWWWPath(string path)
{
#if UNITY_EDITOR
return StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
return path;
#elif UNITY_IPHONE
return StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID
return path;
#elif UNITY_STANDALONE_OSX
return new System.Uri(path).ToString();
#elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path);
#else
return path;
#endif
}
}
}

View File

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

View File

@@ -1,211 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal class PersistentManager
{
private readonly Dictionary<string, string> _cachedDataFilePaths = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _cachedInfoFilePaths = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _tempDataFilePaths = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _buildinFilePaths = new Dictionary<string, string>(10000);
/// <summary>
/// 所属包裹
/// </summary>
public readonly string PackageName;
public string BuildinRoot { private set; get; }
public string BuildinPackageRoot { private set; get; }
public string SandboxRoot { private set; get; }
public string SandboxPackageRoot { private set; get; }
public string SandboxCacheFilesRoot { private set; get; }
public string SandboxManifestFilesRoot { private set; get; }
public string SandboxAppFootPrintFilePath { private set; get; }
public bool AppendFileExtension { private set; get; }
public PersistentManager(string packageName)
{
PackageName = packageName;
}
/// <summary>
/// 初始化
/// </summary>
public void Initialize(string buildinRoot, string sandboxRoot, bool appendFileExtension)
{
if (string.IsNullOrEmpty(buildinRoot))
BuildinRoot = CreateDefaultBuildinRoot();
else
BuildinRoot = buildinRoot;
if (string.IsNullOrEmpty(sandboxRoot))
SandboxRoot = CreateDefaultSandboxRoot();
else
SandboxRoot = sandboxRoot;
BuildinPackageRoot = PathUtility.Combine(BuildinRoot, PackageName);
SandboxPackageRoot = PathUtility.Combine(SandboxRoot, PackageName);
SandboxCacheFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.CacheFilesFolderName);
SandboxManifestFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.ManifestFolderName);
SandboxAppFootPrintFilePath = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.AppFootPrintFileName);
AppendFileExtension = appendFileExtension;
}
private static string CreateDefaultBuildinRoot()
{
return PathUtility.Combine(UnityEngine.Application.streamingAssetsPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
}
private static string CreateDefaultSandboxRoot()
{
#if UNITY_EDITOR
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里。
string projectPath = Path.GetDirectoryName(UnityEngine.Application.dataPath);
projectPath = PathUtility.RegularPath(projectPath);
return PathUtility.Combine(projectPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#elif UNITY_STANDALONE
return PathUtility.Combine(UnityEngine.Application.dataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#else
return PathUtility.Combine(UnityEngine.Application.persistentDataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#endif
}
public string GetCachedDataFilePath(PackageBundle bundle)
{
if (_cachedDataFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
string folderName = bundle.FileHash.Substring(0, 2);
filePath = PathUtility.Combine(SandboxCacheFilesRoot, folderName, bundle.CacheGUID, YooAssetSettings.CacheBundleDataFileName);
if (AppendFileExtension)
filePath += bundle.FileExtension;
_cachedDataFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
public string GetCachedInfoFilePath(PackageBundle bundle)
{
if (_cachedInfoFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
string folderName = bundle.FileHash.Substring(0, 2);
filePath = PathUtility.Combine(SandboxCacheFilesRoot, folderName, bundle.CacheGUID, YooAssetSettings.CacheBundleInfoFileName);
_cachedInfoFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
public string GetTempDataFilePath(PackageBundle bundle)
{
if (_tempDataFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
string cachedDataFilePath = GetCachedDataFilePath(bundle);
filePath = $"{cachedDataFilePath}.temp";
_tempDataFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
public string GetBuildinFilePath(PackageBundle bundle)
{
if (_buildinFilePaths.TryGetValue(bundle.CacheGUID, out string filePath) == false)
{
filePath = PathUtility.Combine(BuildinPackageRoot, bundle.FileName);
_buildinFilePaths.Add(bundle.CacheGUID, filePath);
}
return filePath;
}
/// <summary>
/// 删除沙盒里的包裹目录
/// </summary>
public void DeleteSandboxPackageFolder()
{
if (Directory.Exists(SandboxPackageRoot))
Directory.Delete(SandboxPackageRoot, true);
}
/// <summary>
/// 删除沙盒内的缓存文件夹
/// </summary>
public void DeleteSandboxCacheFilesFolder()
{
if (Directory.Exists(SandboxCacheFilesRoot))
Directory.Delete(SandboxCacheFilesRoot, true);
}
/// <summary>
/// 删除沙盒内的清单文件夹
/// </summary>
public void DeleteSandboxManifestFilesFolder()
{
if (Directory.Exists(SandboxManifestFilesRoot))
Directory.Delete(SandboxManifestFilesRoot, true);
}
/// <summary>
/// 获取沙盒内包裹的清单文件的路径
/// </summary>
public string GetSandboxPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 获取沙盒内包裹的哈希文件的路径
/// </summary>
public string GetSandboxPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 获取沙盒内包裹的版本文件的路径
/// </summary>
public string GetSandboxPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 保存沙盒内默认的包裹版本
/// </summary>
public void SaveSandboxPackageVersionFile(string version)
{
string filePath = GetSandboxPackageVersionFilePath();
FileUtility.WriteAllText(filePath, version);
}
/// <summary>
/// 获取APP内包裹的清单文件的路径
/// </summary>
public string GetBuildinPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
/// <summary>
/// 获取APP内包裹的哈希文件的路径
/// </summary>
public string GetBuildinPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
/// <summary>
/// 获取APP内包裹的版本文件的路径
/// </summary>
public string GetBuildinPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
}
}

View File

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

View File

@@ -1,60 +0,0 @@
using System.IO;
namespace YooAsset
{
/// <summary>
/// 缓存文件验证元素
/// </summary>
internal class VerifyCacheFileElement
{
public string PackageName { private set; get; }
public string CacheGUID { private set; get; }
public string FileRootPath { private set; get; }
public string DataFilePath { private set; get; }
public string InfoFilePath { private set; get; }
public EVerifyResult Result;
public string DataFileCRC;
public long DataFileSize;
public VerifyCacheFileElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath)
{
PackageName = packageName;
CacheGUID = cacheGUID;
FileRootPath = fileRootPath;
DataFilePath = dataFilePath;
InfoFilePath = infoFilePath;
}
public void DeleteFiles()
{
try
{
Directory.Delete(FileRootPath, true);
}
catch (System.Exception e)
{
YooLogger.Warning($"Failed delete cache bundle folder : {e}");
}
}
}
/// <summary>
/// 下载文件验证元素
/// </summary>
internal class VerifyTempFileElement
{
public string TempDataFilePath { private set; get; }
public string FileCRC { private set; get; }
public long FileSize { private set; get; }
public int Result = 0; // 注意:原子操作对象
public VerifyTempFileElement(string tempDataFilePath, string fileCRC, long fileSize)
{
TempDataFilePath = tempDataFilePath;
FileCRC = fileCRC;
FileSize = fileSize;
}
}
}

View File

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

View File

@@ -25,7 +25,7 @@ namespace YooAsset
/// <summary>
/// 加载状态
/// </summary>
public string Status;
public EOperationStatus Status;
public int CompareTo(DebugBundleInfo other)
{

View File

@@ -1,41 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 自定义下载器的请求委托
/// </summary>
public delegate UnityWebRequest DownloadRequestDelegate(string url);
internal static class DownloadHelper
{
/// <summary>
/// 下载失败后清理文件的HTTP错误码
/// </summary>
public static List<long> ClearFileResponseCodes { set; get; }
/// <summary>
/// 自定义下载器的请求委托
/// </summary>
public static DownloadRequestDelegate RequestDelegate = null;
/// <summary>
/// 创建一个新的网络请求
/// </summary>
public static UnityWebRequest NewRequest(string requestURL)
{
UnityWebRequest webRequest;
if (RequestDelegate != null)
webRequest = RequestDelegate.Invoke(requestURL);
else
webRequest = new UnityWebRequest(requestURL, UnityWebRequest.kHttpVerbGET);
return webRequest;
}
}
}

View File

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

View File

@@ -1,150 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 1. 保证每一时刻资源文件只存在一个下载器
/// 2. 保证下载器下载完成后立刻验证并缓存
/// 3. 保证资源文件不会被重复下载
/// </summary>
internal class DownloadManager
{
private readonly Dictionary<string, DownloaderBase> _downloaders = new Dictionary<string, DownloaderBase>(1000);
private readonly List<string> _removeList = new List<string>(1000);
private uint _breakpointResumeFileSize;
/// <summary>
/// 所属包裹
/// </summary>
public readonly string PackageName;
public DownloadManager(string packageName)
{
PackageName = packageName;
}
/// <summary>
/// 初始化
/// </summary>
public void Initialize(uint breakpointResumeFileSize)
{
_breakpointResumeFileSize = breakpointResumeFileSize;
}
/// <summary>
/// 更新下载器
/// </summary>
public void Update()
{
// 更新下载器
_removeList.Clear();
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
downloader.Update();
if (downloader.IsDone())
{
_removeList.Add(valuePair.Key);
}
}
// 移除下载器
foreach (var key in _removeList)
{
_downloaders.Remove(key);
}
}
/// <summary>
/// 销毁所有下载器
/// </summary>
public void DestroyAll()
{
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
downloader.Abort();
}
_downloaders.Clear();
_removeList.Clear();
}
/// <summary>
/// 创建下载器
/// 注意:只有第一次请求的参数才有效
/// </summary>
public DownloaderBase CreateDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
{
// 查询存在的下载器
if (_downloaders.TryGetValue(bundleInfo.CachedDataFilePath, out var downloader))
{
downloader.Reference();
return downloader;
}
// 如果资源已经缓存
if (bundleInfo.IsCached())
{
var completedDownloader = new CompletedDownloader(bundleInfo);
return completedDownloader;
}
// 创建新的下载器
DownloaderBase newDownloader = null;
YooLogger.Log($"Beginning to download bundle : {bundleInfo.Bundle.BundleName} URL : {bundleInfo.RemoteMainURL}");
#if UNITY_WEBGL
if (bundleInfo.Bundle.Buildpipeline == EDefaultBuildPipeline.RawFileBuildPipeline.ToString())
{
FileUtility.CreateFileDirectory(bundleInfo.CachedDataFilePath);
System.Type requesterType = typeof(FileGeneralRequest);
newDownloader = new FileDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
else
{
System.Type requesterType = typeof(AssetBundleWebRequest);
newDownloader = new WebDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
#else
FileUtility.CreateFileDirectory(bundleInfo.CachedDataFilePath);
bool resumeDownload = bundleInfo.Bundle.FileSize >= _breakpointResumeFileSize;
if (resumeDownload)
{
System.Type requesterType = typeof(FileResumeRequest);
newDownloader = new FileDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
else
{
System.Type requesterType = typeof(FileGeneralRequest);
newDownloader = new FileDownloader(bundleInfo, requesterType, failedTryAgain, timeout);
}
#endif
// 返回新创建的下载器
_downloaders.Add(bundleInfo.CachedDataFilePath, newDownloader);
newDownloader.Reference();
return newDownloader;
}
/// <summary>
/// 停止不再使用的下载器
/// </summary>
public void AbortUnusedDownloader()
{
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
if (downloader.RefCount <= 0)
{
downloader.Abort();
}
}
}
}
}

View File

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

View File

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

namespace YooAsset
{
internal class DownloadParam
{
public readonly int FailedTryAgain;
public readonly int Timeout;
/// <summary>
/// 导入的本地文件路径
/// </summary>
public string ImportFilePath { set; get; }
/// <summary>
/// 主资源地址
/// </summary>
public string MainURL { set; get; }
/// <summary>
/// 备用资源地址
/// </summary>
public string FallbackURL { set; get; }
public DownloadParam(int failedTryAgain, int timeout)
{
FailedTryAgain = failedTryAgain;
Timeout = timeout;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e4a97c06e069c1146a881fcb359f9b4b
guid: 56ea224b45d314e4a86b558404e9b6c8
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,50 @@
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 自定义下载器的请求委托
/// </summary>
public delegate UnityWebRequest UnityWebRequestDelegate(string url);
internal class DownloadSystemHelper
{
public static UnityWebRequestDelegate UnityWebRequestCreater = null;
public static UnityWebRequest NewUnityWebRequestGet(string requestURL)
{
UnityWebRequest webRequest;
if (UnityWebRequestCreater != null)
webRequest = UnityWebRequestCreater.Invoke(requestURL);
else
webRequest = new UnityWebRequest(requestURL, UnityWebRequest.kHttpVerbGET);
return webRequest;
}
/// <summary>
/// 获取WWW加载本地资源的路径
/// </summary>
public static string ConvertToWWWPath(string path)
{
#if UNITY_EDITOR
return StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
return path;
#elif UNITY_IPHONE
return StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID
if (path.StartsWith("jar:file://"))
return path;
else
return StringUtility.Format("jar:file://{0}", path);
#elif UNITY_STANDALONE_OSX
return new System.Uri(path).ToString();
#elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path);
#elif UNITY_OPENHARMONY
return StringUtility.Format("file://{0}", path);
#else
throw new System.NotImplementedException();
#endif
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 08f3e92fdbd5d56459d8882be1f54f60
guid: 5bacfa8c42e283a45a2d21cbb93d6e5d
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,28 +0,0 @@
using UnityEngine;
namespace YooAsset
{
internal sealed class CompletedDownloader : DownloaderBase
{
public CompletedDownloader(BundleInfo bundleInfo) : base(bundleInfo, null, 0, 0)
{
DownloadProgress = 1f;
DownloadedBytes = (ulong)bundleInfo.Bundle.FileSize;
_status = EStatus.Succeed;
}
public override void SendRequest(params object[] param)
{
}
public override void Update()
{
}
public override void Abort()
{
}
public override AssetBundle GetAssetBundle()
{
throw new System.NotImplementedException();
}
}
}

View File

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

View File

@@ -1,182 +0,0 @@
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal abstract class DownloaderBase
{
public enum EStatus
{
None = 0,
Succeed,
Failed
}
protected readonly BundleInfo _bundleInfo;
protected readonly System.Type _requesterType;
protected readonly int _timeout;
protected int _failedTryAgain;
protected IWebRequester _requester;
protected EStatus _status = EStatus.None;
protected string _lastestNetError = string.Empty;
protected long _lastestHttpCode = 0;
// 请求次数
protected int _requestCount = 0;
protected string _requestURL;
// 超时相关
protected bool _isAbort = false;
protected ulong _latestDownloadBytes;
protected float _latestDownloadRealtime;
protected float _tryAgainTimer;
/// <summary>
/// 是否等待异步结束
/// 警告只能用于解压APP内部资源
/// </summary>
public bool WaitForAsyncComplete = false;
/// <summary>
/// 下载进度0f~1f
/// </summary>
public float DownloadProgress { protected set; get; }
/// <summary>
/// 已经下载的总字节数
/// </summary>
public ulong DownloadedBytes { protected set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
public DownloaderBase(BundleInfo bundleInfo, System.Type requesterType, int failedTryAgain, int timeout)
{
_bundleInfo = bundleInfo;
_requesterType = requesterType;
_failedTryAgain = failedTryAgain;
_timeout = timeout;
}
public abstract void SendRequest(params object[] args);
public abstract void Update();
public abstract void Abort();
public abstract AssetBundle GetAssetBundle();
/// <summary>
/// 引用(引用计数递加)
/// </summary>
public void Reference()
{
RefCount++;
}
/// <summary>
/// 释放(引用计数递减)
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 检测下载器是否已经完成(无论成功或失败)
/// </summary>
public bool IsDone()
{
return _status == EStatus.Succeed || _status == EStatus.Failed;
}
/// <summary>
/// 下载过程是否发生错误
/// </summary>
public bool HasError()
{
return _status == EStatus.Failed;
}
/// <summary>
/// 按照错误级别打印错误
/// </summary>
public void ReportError()
{
YooLogger.Error(GetLastError());
}
/// <summary>
/// 按照警告级别打印错误
/// </summary>
public void ReportWarning()
{
YooLogger.Warning(GetLastError());
}
/// <summary>
/// 获取最近发生的错误信息
/// </summary>
public string GetLastError()
{
return $"Failed to download : {_requestURL} Error : {_lastestNetError} Code : {_lastestHttpCode}";
}
/// <summary>
/// 获取下载文件的大小
/// </summary>
/// <returns></returns>
public long GetDownloadFileSize()
{
return _bundleInfo.Bundle.FileSize;
}
/// <summary>
/// 获取下载的资源包名称
/// </summary>
public string GetDownloadBundleName()
{
return _bundleInfo.Bundle.BundleName;
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _bundleInfo.RemoteFallbackURL;
else
return _bundleInfo.RemoteMainURL;
}
/// <summary>
/// 超时判定方法
/// </summary>
protected void CheckTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != DownloadedBytes)
{
_latestDownloadBytes = DownloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout)
{
YooLogger.Warning($"Web file request timeout : {_requestURL}");
if (_requester != null)
_requester.Abort();
_isAbort = true;
}
}
}
}
}

View File

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

View File

@@ -1,216 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 文件下载器
/// </summary>
internal sealed class FileDownloader : DownloaderBase
{
private enum ESteps
{
None,
PrepareDownload,
CreateDownloader,
CheckDownload,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
Done,
}
private VerifyTempFileOperation _verifyFileOp = null;
private ESteps _steps = ESteps.None;
public FileDownloader(BundleInfo bundleInfo, System.Type requesterType, int failedTryAgain, int timeout) : base(bundleInfo, requesterType, failedTryAgain, timeout)
{
}
public override void SendRequest(params object[] args)
{
if (_steps == ESteps.None)
{
_steps = ESteps.PrepareDownload;
}
}
public override void Update()
{
if (_steps == ESteps.None)
return;
if (IsDone())
return;
// 准备下载
if (_steps == ESteps.PrepareDownload)
{
// 获取请求地址
_requestURL = GetRequestURL();
// 重置变量
DownloadProgress = 0f;
DownloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
// 重置计时器
if (_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
_steps = ESteps.CreateDownloader;
}
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
_requester = (IWebRequester)Activator.CreateInstance(_requesterType);
_requester.Create(_requestURL, _bundleInfo);
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_requester.Update();
DownloadedBytes = _requester.DownloadedBytes;
DownloadProgress = _requester.DownloadProgress;
if (_requester.IsDone() == false)
{
CheckTimeout();
return;
}
_lastestNetError = _requester.RequestNetError;
_lastestHttpCode = _requester.RequestHttpCode;
if (_requester.Status != ERequestStatus.Success)
{
_steps = ESteps.TryAgain;
}
else
{
_steps = ESteps.VerifyTempFile;
}
}
// 验证下载文件
if (_steps == ESteps.VerifyTempFile)
{
VerifyTempFileElement element = new VerifyTempFileElement(_bundleInfo.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
_verifyFileOp = VerifyTempFileOperation.CreateOperation(element);
OperationSystem.StartOperation(_bundleInfo.Bundle.PackageName, _verifyFileOp);
_steps = ESteps.WaitingVerifyTempFile;
}
// 等待验证完成
if (_steps == ESteps.WaitingVerifyTempFile)
{
if (WaitForAsyncComplete)
_verifyFileOp.InternalOnUpdate();
if (_verifyFileOp.IsDone == false)
return;
if (_verifyFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CachingFile;
}
else
{
string tempFilePath = _bundleInfo.TempDataFilePath;
if (File.Exists(tempFilePath))
File.Delete(tempFilePath);
_lastestNetError = _verifyFileOp.Error;
_steps = ESteps.TryAgain;
}
}
// 缓存下载文件
if (_steps == ESteps.CachingFile)
{
try
{
CachingFile();
_status = EStatus.Succeed;
_steps = ESteps.Done;
}
catch (Exception e)
{
_lastestNetError = e.Message;
_steps = ESteps.TryAgain;
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
if (_failedTryAgain <= 0)
{
ReportError();
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
}
}
}
public override void Abort()
{
if (_requester != null)
_requester.Abort();
if (IsDone() == false)
{
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastestNetError = "user abort";
_lastestHttpCode = 0;
}
}
public override AssetBundle GetAssetBundle()
{
throw new NotImplementedException();
}
/// <summary>
/// 缓存下载文件
/// </summary>
private void CachingFile()
{
string tempFilePath = _bundleInfo.TempDataFilePath;
string infoFilePath = _bundleInfo.CachedInfoFilePath;
string dataFilePath = _bundleInfo.CachedDataFilePath;
string dataFileCRC = _bundleInfo.Bundle.FileCRC;
long dataFileSize = _bundleInfo.Bundle.FileSize;
if (File.Exists(infoFilePath))
File.Delete(infoFilePath);
if (File.Exists(dataFilePath))
File.Delete(dataFilePath);
// 移动临时文件路径
FileInfo fileInfo = new FileInfo(tempFilePath);
fileInfo.MoveTo(dataFilePath);
// 写入信息文件记录验证数据
CacheFileInfo.WriteInfoToFile(infoFilePath, dataFileCRC, dataFileSize);
// 记录缓存文件
_bundleInfo.CacheRecord();
}
}
}

View File

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

View File

@@ -1,140 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal sealed class WebDownloader : DownloaderBase
{
private enum ESteps
{
None,
PrepareDownload,
CreateDownloader,
CheckDownload,
TryAgain,
Done,
}
private ESteps _steps = ESteps.None;
private bool _getAssetBundle = false;
public WebDownloader(BundleInfo bundleInfo, System.Type requesterType, int failedTryAgain, int timeout) : base(bundleInfo, requesterType, failedTryAgain, timeout)
{
}
public override void SendRequest(params object[] args)
{
if (_steps == ESteps.None)
{
if (args.Length > 0)
{
_getAssetBundle = (bool)args[0];
}
_steps = ESteps.PrepareDownload;
}
}
public override void Update()
{
if (_steps == ESteps.None)
return;
if (IsDone())
return;
// 创建下载器
if (_steps == ESteps.PrepareDownload)
{
// 获取请求地址
_requestURL = GetRequestURL();
// 重置变量
DownloadProgress = 0f;
DownloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
// 重置计时器
if (_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
_steps = ESteps.CreateDownloader;
}
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
_requester = (IWebRequester)Activator.CreateInstance(_requesterType);
_requester.Create(_requestURL, _bundleInfo, _getAssetBundle);
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_requester.Update();
DownloadedBytes = _requester.DownloadedBytes;
DownloadProgress = _requester.DownloadProgress;
if (_requester.IsDone() == false)
{
CheckTimeout();
return;
}
_lastestNetError = _requester.RequestNetError;
_lastestHttpCode = _requester.RequestHttpCode;
if (_requester.Status != ERequestStatus.Success)
{
_steps = ESteps.TryAgain;
}
else
{
_status = EStatus.Succeed;
_steps = ESteps.Done;
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
if (_failedTryAgain <= 0)
{
ReportError();
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
YooLogger.Warning($"Try again download : {_requestURL}");
}
}
}
public override void Abort()
{
if (_requester != null)
_requester.Abort();
if (IsDone() == false)
{
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastestNetError = "user abort";
_lastestHttpCode = 0;
}
}
public override AssetBundle GetAssetBundle()
{
return (AssetBundle)_requester.GetRequestObject();
}
}
}

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d29a9623b2b346e439b7a7e37fafa781
guid: a8f060786f8775b4a82cc3f55d9135e2
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a93a516506b2b5c4492fdefe26eb1175
guid: 4630dac2050606043bb146325fdce6ad
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,77 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebDataRequestOperation : UnityWebRequestOperation
{
private UnityWebRequestAsyncOperation _requestOperation;
/// <summary>
/// 请求结果
/// </summary>
public byte[] Result { private set; get; }
internal UnityWebDataRequestOperation(string url, int timeout = 60) : base(url, timeout)
{
}
internal override void InternalOnStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
_steps = ESteps.Done;
Result = _webRequest.downloadHandler.data;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
internal override void InternalOnAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
}
}

View File

@@ -0,0 +1,73 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebFileRequestOperation : UnityWebRequestOperation
{
private UnityWebRequestAsyncOperation _requestOperation;
private readonly string _fileSavePath;
internal UnityWebFileRequestOperation(string url, string fileSavePath, int timeout = 60) : base(url, timeout)
{
_fileSavePath = fileSavePath;
}
internal override void InternalOnStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
internal override void InternalOnAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(_fileSavePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
}
}

View File

@@ -6,99 +6,58 @@ using UnityEngine;
namespace YooAsset
{
internal abstract class UnityWebRequesterBase
internal abstract class UnityWebRequestOperation : AsyncOperationBase
{
protected enum ESteps
{
None,
CreateRequest,
Download,
Done,
}
protected UnityWebRequest _webRequest;
protected UnityWebRequestAsyncOperation _operationHandle;
protected readonly string _requestURL;
protected ESteps _steps = ESteps.None;
// 超时相关
private float _timeout;
protected readonly float _timeout;
protected ulong _latestDownloadBytes;
protected float _latestDownloadRealtime;
private bool _isAbort = false;
private ulong _latestDownloadBytes;
private float _latestDownloadRealtime;
/// <summary>
/// 请求URL地址
/// </summary>
public string URL { protected set; get; }
protected void ResetTimeout(float timeout)
public string URL
{
get { return _requestURL; }
}
internal UnityWebRequestOperation(string url, int timeout)
{
_requestURL = url;
_timeout = timeout;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
/// <summary>
/// 释放下载器
/// </summary>
public void Dispose()
protected void DisposeRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
_operationHandle = null;
}
}
/// <summary>
/// 是否完毕(无论成功失败)
/// </summary>
public bool IsDone()
{
if (_operationHandle == null)
return false;
return _operationHandle.isDone;
}
/// <summary>
/// 下载进度
/// </summary>
public float Progress()
{
if (_operationHandle == null)
return 0;
return _operationHandle.progress;
}
/// <summary>
/// 下载是否发生错误
/// </summary>
public bool HasError()
{
#if UNITY_2020_3_OR_NEWER
return _webRequest.result != UnityWebRequest.Result.Success;
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
return true;
else
return false;
#endif
}
/// <summary>
/// 获取错误信息
/// </summary>
public string GetError()
{
if (_webRequest != null)
{
return $"URL : {URL} Error : {_webRequest.error}";
}
return string.Empty;
}
/// <summary>
/// 检测超时
/// </summary>
public void CheckTimeout()
protected void CheckRequestTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != _webRequest.downloadedBytes)
if ( _latestDownloadBytes != _webRequest.downloadedBytes)
{
_latestDownloadBytes = _webRequest.downloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
@@ -112,5 +71,33 @@ namespace YooAsset
}
}
}
/// <summary>
/// 检测请求结果
/// </summary>
protected bool CheckRequestResult()
{
#if UNITY_2020_3_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
{
Error = $"URL : {_requestURL} Error : {_webRequest.error}";
return false;
}
else
{
return true;
}
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
Error = $"URL : {_requestURL} Error : {_webRequest.error}";
return false;
}
else
{
return true;
}
#endif
}
}
}

View File

@@ -0,0 +1,77 @@
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebTextRequestOperation : UnityWebRequestOperation
{
private UnityWebRequestAsyncOperation _requestOperation;
/// <summary>
/// 请求结果
/// </summary>
public string Result { private set; get; }
internal UnityWebTextRequestOperation(string url, int timeout = 60) : base(url, timeout)
{
}
internal override void InternalOnStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CreateRequest)
{
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
CreateWebRequest();
_steps = ESteps.Download;
}
if (_steps == ESteps.Download)
{
Progress = _requestOperation.progress;
if (_requestOperation.isDone == false)
{
CheckRequestTimeout();
return;
}
if (CheckRequestResult())
{
_steps = ESteps.Done;
Result = _webRequest.downloadHandler.text;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
}
// 注意:最终释放请求器
DisposeRequest();
}
}
internal override void InternalOnAbort()
{
_steps = ESteps.Done;
DisposeRequest();
}
private void CreateWebRequest()
{
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_requestOperation = _webRequest.SendWebRequest();
}
}
}

View File

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

View File

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

View File

@@ -1,145 +0,0 @@
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal class AssetBundleWebRequest : IWebRequester
{
private UnityWebRequest _webRequest;
private DownloadHandlerAssetBundle _downloadhandler;
private AssetBundle _cacheAssetBundle;
private bool _getAssetBundle = false;
public ERequestStatus Status { private set; get; } = ERequestStatus.None;
public float DownloadProgress { private set; get; }
public ulong DownloadedBytes { private set; get; }
public string RequestNetError { private set; get; }
public long RequestHttpCode { private set; get; }
public AssetBundleWebRequest() { }
public void Create(string requestURL, BundleInfo bundleInfo, params object[] args)
{
if (Status != ERequestStatus.None)
throw new System.Exception("Should never get here !");
if (args.Length == 0)
throw new System.Exception("Not found param value");
// 解析附加参数
_getAssetBundle = (bool)args[0];
// 创建下载器
_webRequest = DownloadHelper.NewRequest(requestURL);
if (CacheHelper.DisableUnityCacheOnWebGL)
{
uint crc = bundleInfo.Bundle.UnityCRC;
_downloadhandler = new DownloadHandlerAssetBundle(requestURL, crc);
}
else
{
uint crc = bundleInfo.Bundle.UnityCRC;
var hash = Hash128.Parse(bundleInfo.Bundle.FileHash);
_downloadhandler = new DownloadHandlerAssetBundle(requestURL, hash, crc);
}
#if UNITY_2020_3_OR_NEWER
_downloadhandler.autoLoadAssetBundle = false;
#endif
_webRequest.downloadHandler = _downloadhandler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
Status = ERequestStatus.InProgress;
}
public void Update()
{
if (Status == ERequestStatus.None)
return;
if (IsDone())
return;
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.result != UnityWebRequest.Result.Success)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#else
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#endif
// 缓存加载的AssetBundle对象
if (Status == ERequestStatus.Success)
{
if (_getAssetBundle)
{
_cacheAssetBundle = _downloadhandler.assetBundle;
if (_cacheAssetBundle == null)
{
RequestNetError = "assetBundle is null";
Status = ERequestStatus.Error;
}
}
}
// 最终释放下载器
DisposeWebRequest();
}
public void Abort()
{
// 如果下载任务还未开始
if (Status == ERequestStatus.None)
{
RequestNetError = "user cancel";
Status = ERequestStatus.Error;
}
else
{
// 注意:为了防止同一个文件强制停止之后立马创建新的请求,应该让进行中的请求自然终止。
if (_webRequest != null)
{
if (_webRequest.isDone == false)
_webRequest.Abort(); // If in progress, halts the UnityWebRequest as soon as possible.
}
}
}
public bool IsDone()
{
if (Status == ERequestStatus.Success || Status == ERequestStatus.Error)
return true;
else
return false;
}
public object GetRequestObject()
{
return _cacheAssetBundle;
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -1,107 +0,0 @@
using System.IO;
using UnityEngine.Networking;
namespace YooAsset
{
internal class FileGeneralRequest : IWebRequester
{
private UnityWebRequest _webRequest;
public ERequestStatus Status { private set; get; } = ERequestStatus.None;
public float DownloadProgress { private set; get; }
public ulong DownloadedBytes { private set; get; }
public string RequestNetError { private set; get; }
public long RequestHttpCode { private set; get; }
public FileGeneralRequest() { }
public void Create(string requestURL, BundleInfo bundleInfo, params object[] args)
{
if (Status != ERequestStatus.None)
throw new System.Exception("Should never get here !");
string tempFilePath = bundleInfo.TempDataFilePath;
// 删除临时文件
if (File.Exists(tempFilePath))
File.Delete(tempFilePath);
// 创建下载器
_webRequest = DownloadHelper.NewRequest(requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(tempFilePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
Status = ERequestStatus.InProgress;
}
public void Update()
{
if (Status == ERequestStatus.None)
return;
if (IsDone())
return;
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.result != UnityWebRequest.Result.Success)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#else
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#endif
// 最终释放下载器
DisposeWebRequest();
}
public void Abort()
{
DisposeWebRequest();
if (IsDone() == false)
{
RequestNetError = "user abort";
RequestHttpCode = 0;
Status = ERequestStatus.Error;
}
}
public bool IsDone()
{
if (Status == ERequestStatus.Success || Status == ERequestStatus.Error)
return true;
else
return false;
}
public object GetRequestObject()
{
throw new System.NotImplementedException();
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose(); //注意引擎底层会自动调用Abort方法
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -1,150 +0,0 @@
using System.IO;
using UnityEngine.Networking;
namespace YooAsset
{
internal class FileResumeRequest : IWebRequester
{
private string _tempFilePath;
private UnityWebRequest _webRequest;
private DownloadHandlerFileRange _downloadHandle;
private ulong _fileOriginLength = 0;
public ERequestStatus Status { private set; get; } = ERequestStatus.None;
public float DownloadProgress { private set; get; }
public ulong DownloadedBytes { private set; get; }
public string RequestNetError { private set; get; }
public long RequestHttpCode { private set; get; }
public FileResumeRequest() { }
public void Create(string requestURL, BundleInfo bundleInfo, params object[] args)
{
if (Status != ERequestStatus.None)
throw new System.Exception("Should never get here !");
_tempFilePath = bundleInfo.TempDataFilePath;
long fileBytes = bundleInfo.Bundle.FileSize;
// 获取下载的起始位置
long fileLength = -1;
if (File.Exists(_tempFilePath))
{
FileInfo fileInfo = new FileInfo(_tempFilePath);
fileLength = fileInfo.Length;
_fileOriginLength = (ulong)fileLength;
DownloadedBytes = _fileOriginLength;
}
// 检测下载起始位置是否有效
if (fileLength >= fileBytes)
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
// 创建下载器
_webRequest = DownloadHelper.NewRequest(requestURL);
#if UNITY_2019_4_OR_NEWER
var handler = new DownloadHandlerFile(_tempFilePath, true);
handler.removeFileOnAbort = false;
#else
var handler = new DownloadHandlerFileRange(tempFilePath, _bundleInfo.Bundle.FileSize, _webRequest);
_downloadHandle = handler;
#endif
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
if (fileLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={fileLength}-");
_webRequest.SendWebRequest();
Status = ERequestStatus.InProgress;
}
public void Update()
{
if (Status == ERequestStatus.None)
return;
if (IsDone())
return;
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _fileOriginLength + _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.result != UnityWebRequest.Result.Success)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#else
RequestHttpCode = _webRequest.responseCode;
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
RequestNetError = _webRequest.error;
Status = ERequestStatus.Error;
}
else
{
Status = ERequestStatus.Success;
}
#endif
// 注意:下载断点续传文件发生特殊错误码之后删除文件
if (Status == ERequestStatus.Error)
{
if (DownloadHelper.ClearFileResponseCodes != null)
{
if (DownloadHelper.ClearFileResponseCodes.Contains(RequestHttpCode))
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
}
// 最终释放下载器
DisposeWebRequest();
}
public void Abort()
{
DisposeWebRequest();
if (IsDone() == false)
{
RequestNetError = "user abort";
RequestHttpCode = 0;
Status = ERequestStatus.Error;
}
}
public bool IsDone()
{
if (Status == ERequestStatus.Success || Status == ERequestStatus.Error)
return true;
else
return false;
}
public object GetRequestObject()
{
throw new System.NotImplementedException();
}
private void DisposeWebRequest()
{
if (_downloadHandle != null)
{
_downloadHandle.Cleanup();
_downloadHandle = null;
}
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
}
}
}
}

View File

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

View File

@@ -1,65 +0,0 @@

namespace YooAsset
{
internal enum ERequestStatus
{
None,
InProgress,
Error,
Success,
}
internal interface IWebRequester
{
/// <summary>
/// 任务状态
/// </summary>
public ERequestStatus Status { get; }
/// <summary>
/// 下载进度0f~1f
/// </summary>
public float DownloadProgress { get; }
/// <summary>
/// 已经下载的总字节数
/// </summary>
public ulong DownloadedBytes { get; }
/// <summary>
/// 返回的网络错误
/// </summary>
public string RequestNetError { get; }
/// <summary>
/// 返回的HTTP CODE
/// </summary>
public long RequestHttpCode { get; }
/// <summary>
/// 创建任务
/// </summary>
public void Create(string url, BundleInfo bundleInfo, params object[] args);
/// <summary>
/// 更新任务
/// </summary>
public void Update();
/// <summary>
/// 终止任务
/// </summary>
public void Abort();
/// <summary>
/// 是否已经完成(无论成功或失败)
/// </summary>
public bool IsDone();
/// <summary>
/// 获取请求的对象
/// </summary>
public object GetRequestObject();
}
}

View File

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

View File

@@ -1,51 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebDataRequester : UnityWebRequesterBase
{
/// <summary>
/// 发送GET请求
/// </summary>
public void SendRequest(string url, int timeout = 60)
{
if (_webRequest == null)
{
URL = url;
ResetTimeout(timeout);
_webRequest = DownloadHelper.NewRequest(URL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_operationHandle = _webRequest.SendWebRequest();
}
}
/// <summary>
/// 获取下载的字节数据
/// </summary>
public byte[] GetData()
{
if (_webRequest != null && IsDone())
return _webRequest.downloadHandler.data;
else
return null;
}
/// <summary>
/// 获取下载的文本数据
/// </summary>
public string GetText()
{
if (_webRequest != null && IsDone())
return _webRequest.downloadHandler.text;
else
return null;
}
}
}

View File

@@ -1,30 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal class UnityWebFileRequester : UnityWebRequesterBase
{
/// <summary>
/// 发送GET请求
/// </summary>
public void SendRequest(string url, string fileSavePath, int timeout = 60)
{
if (_webRequest == null)
{
URL = url;
ResetTimeout(timeout);
_webRequest = DownloadHelper.NewRequest(URL);
DownloadHandlerFile handler = new DownloadHandlerFile(fileSavePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_operationHandle = _webRequest.SendWebRequest();
}
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace YooAsset
{
public class RequestHelper
internal class WebRequestCounter
{
/// <summary>
/// 记录网络请求失败事件的次数

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