Compare commits

...

41 Commits
1.0.1 ... 1.0.5

Author SHA1 Message Date
hevinci
469d73d641 Update CHANGELOG.md 2022-04-22 18:16:31 +08:00
hevinci
0d521c68bd Update package.json 2022-04-22 18:16:25 +08:00
hevinci
cd62c1dd9a Update AssetSystem 2022-04-22 16:43:09 +08:00
hevinci
e6422445a6 Added debugging information
新增调试信息,出生场景和出生时间。
2022-04-22 16:22:09 +08:00
hevinci
7683746032 Support do a dry run build.
支持演练构建模式。
2022-04-22 15:14:37 +08:00
hevinci
a25fd19bcc Fixed an issue with task asyn loading waiting 2022-04-21 21:55:48 +08:00
hevinci
6675e8f171 Fixed an issue with task asyn loading waiting 2022-04-21 21:39:00 +08:00
hevinci
c836dce54d Fixed an issue with task asyn loading waiting
修复Task异步加载一直等待的问题。
2022-04-21 21:27:53 +08:00
hevinci
f3ab8f63e7 Optimize the scene unload logic.
优化场景卸载逻辑,在加载新的主场景的时候自动卸载已经加载的所有场景。
2022-04-21 21:11:11 +08:00
hevinci
20d2c517b2 Optimized raw file load logic
优化原生文件加载逻辑,支持离线运行模式和编辑器运行模式。
2022-04-21 16:16:40 +08:00
hevinci
d6a2b31d5c Add editor extend properties
增加编辑器扩展的支持
2022-04-19 10:11:24 +08:00
hevinci
533f96361a Update AssetBundleWindow
修复了非主动收集的着色器没有打进统一的着色器资源包的问题。
修复了单个收集的资源对象没有设置依赖资源列表的问题。
资源打包的过滤文件列表增加cginc格式。
2022-04-18 19:48:37 +08:00
hevinci
09807901c0 Update README.md 2022-04-18 16:01:48 +08:00
hevinci
57ae9aa18c Update CHANGELOG.md 2022-04-18 15:51:40 +08:00
hevinci
08efcaf4c1 Update package.json 2022-04-18 15:51:38 +08:00
hevinci
b221b8121a Update bundleInfo
修复原生文件拷贝目录不存导致的加载失败
完善原生文件异步加载接口
2022-04-18 15:08:39 +08:00
hevinci
abb75fe858 Fixed a process error raised after the additional version of the patch manifest
修复资源清单附加版本之后引发的一个流程错误。
2022-04-18 09:58:44 +08:00
hevinci
4591d0b5f6 Check location param is invalid.
在编辑器下检测资源路径是否合法并警告。
2022-04-14 19:01:39 +08:00
hevinci
b25f656372 Update package.json 2022-04-14 14:44:48 +08:00
hevinci
cc1c8d6414 Update CHANGELOG.md 2022-04-14 14:44:44 +08:00
hevinci
99a3abf697 Resource location interface extension 2022-04-14 14:06:23 +08:00
hevinci
023dc82f8e Update document 2022-04-14 12:38:20 +08:00
hevinci
09a985fadb Resource location interface extension
资源定位接口扩展
2022-04-14 12:19:04 +08:00
hevinci
eb6b6e3aba Fixed special case where the dependent bundle list contained the main bundle
修复了特殊情况下依赖的资源包列表里包含主资源包的问题
2022-04-13 17:00:14 +08:00
hevinci
89bde69417 Update AssetBundleBuilder
保留构建窗口界面的配置数据
2022-04-13 16:19:57 +08:00
hevinci
6bb3c17f82 Update document 2022-04-12 19:41:00 +08:00
hevinci
8be6d54f22 Update document 2022-04-12 19:36:18 +08:00
hevinci
ea28d3e6e1 Simplify the concept of resource version
简化资源版本概念
2022-04-12 19:15:44 +08:00
hevinci
9fbce6a726 offline play mode supports WebGL platform.
离线运行模式支持WEBGL平台。
2022-04-12 10:53:12 +08:00
hevinci
46467171ba Update AssetBundleDebugger
修复了AssetBundleDebugger窗口的BundleView视口下,Bundle列表内元素重复的问题。
修复了AssetBundleDebugger窗口的BundleView视口下,Using列表显示不完整的问题。
2022-04-09 14:30:46 +08:00
hevinci
d2d6d2ad14 Update AssetBundleGrouper
优化了资源分组配置保存策略
2022-04-09 12:02:02 +08:00
hevinci
f38d663e9d Update AssetSystem
实例化GameObject的时候,如果没有传递坐标和角度则使用默认值。
2022-04-08 19:10:00 +08:00
hevinci
11e03c7a13 Update README.md 2022-04-07 20:41:10 +08:00
hevinci
f466a02fd7 Update document 2022-04-07 20:35:20 +08:00
hevinci
3bb4d5082b Update README.md 2022-04-07 20:35:10 +08:00
hevinci
fb743ada63 Update CHANGELOG.md 2022-04-07 19:26:19 +08:00
hevinci
a17e742218 Update package.json 2022-04-07 19:26:16 +08:00
hevinci
d6b54dd49c Update AssetBundleTools
StreamingAssets目录下增加了用于存放打包资源的总文件夹
2022-04-07 19:18:33 +08:00
hevinci
b7a20d4bdb Update AssetBundleTools
修复了资源分组在特殊情况下打包报错的问题
2022-04-07 19:15:24 +08:00
hevinci
28c22694ba Update AssetSystem
修复在资源加载完成回调内释放自身资源句柄时的异常报错。
2022-04-07 14:24:09 +08:00
hevinci
efd0789e09 Update document 2022-04-07 12:05:21 +08:00
102 changed files with 2744 additions and 1315 deletions

View File

@@ -2,6 +2,66 @@
All notable changes to this package will be documented in this file.
## [1.0.5] - 2022-04-22
### Fixed
- 修复了非主动收集的着色器没有打进统一的着色器资源包的问题。
- 修复了单个收集的资源对象没有设置依赖资源列表的问题。
- 修复Task异步加载一直等待的问题。
### Changed
- 资源打包的过滤文件列表增加cginc格式。
- 增加编辑器扩展的支持第三方实现YooAsset插件。
- 优化原生文件加载逻辑,支持离线运行模式和编辑器运行模式。
- 优化场景卸载逻辑,在加载新的主场景的时候自动卸载已经加载的所有场景。
- 支持演练构建模式,在不生成资源包的情况下快速构建查看结果。
- 新增调试信息,出生场景和出生时间。
## [1.0.4] - 2022-04-18
### Fixed
- 修复资源清单附加版本之后引发的一个流程错误。
- 修复原生文件拷贝目录不存导致的加载失败。
### Changed
- 在编辑器下检测资源路径是否合法并警告。
- 完善原生文件异步加载接口。
## [1.0.3] - 2022-04-14
### Fixed
- 修复了AssetBundleDebugger窗口的BundleView视口下Using列表显示不完整的问题。
- 修复了AssetBundleDebugger窗口的BundleView视口下Bundle列表内元素重复的问题。
- 修复了特殊情况下依赖的资源包列表里包含主资源包的问题。
### Changed
- 实例化GameObject的时候如果没有传递坐标和角度则使用默认值。
- 优化了资源分组配置保存策略,修改为窗口关闭时保存。
- 简化了资源版本概念降低学习成本统一了CDN上的目录结构。
- 资源定位接口扩展,方便开发可寻址资产定位功能。
### Added
- 离线运行模式支持WEBGL平台。
- 保留构建窗口界面的配置数据。
## [1.0.2] - 2022-04-07
### Fixed
- 修复在资源加载完成回调内释放自身资源句柄时的异常报错。
- 修复了资源分组在特殊情况下打包报错的问题。
### Changed
- StreamingAssets目录下增加了用于存放打包资源的总文件夹。
## [1.0.1] - 2022-04-07
### Fixed

View File

@@ -48,6 +48,12 @@ namespace YooAsset.Editor
BuildAssetBundleOptions opt = BuildAssetBundleOptions.None;
opt |= BuildAssetBundleOptions.StrictMode; //Do not allow the build to succeed if any errors are reporting during it.
if (Parameters.DryRunBuild)
{
opt |= BuildAssetBundleOptions.DryRunBuild;
return opt;
}
if (Parameters.CompressOption == ECompressOption.Uncompressed)
opt |= BuildAssetBundleOptions.UncompressedAssetBundle;
else if (Parameters.CompressOption == ECompressOption.LZ4)
@@ -107,7 +113,8 @@ namespace YooAsset.Editor
{
new TaskPrepare(), //前期准备工作
new TaskGetBuildMap(), //获取构建列表
new TaskBuilding(), //开始执行构建
new TaskBuilding(), //开始执行构建
new TaskVerifyBuildResult(), //验证构建结果
new TaskEncryption(), //加密资源文件
new TaskCreatePatchManifest(), //创建清单文件
new TaskCreateReport(), //创建报告文件

View File

@@ -17,6 +17,14 @@ namespace YooAsset.Editor
return $"{projectPath}/Bundles";
}
/// <summary>
/// 获取流文件夹路径
/// </summary>
public static string GetStreamingAssetsFolderPath()
{
return $"{Application.dataPath}/StreamingAssets/YooAssets/";
}
/// <summary>
/// 获取构建管线的输出目录
/// </summary>
@@ -30,8 +38,8 @@ namespace YooAsset.Editor
/// </summary>
public static void ClearStreamingAssetsFolder()
{
string streamingPath = Application.dataPath + "/StreamingAssets";
EditorTools.ClearFolder(streamingPath);
string streamingFolderPath = GetStreamingAssetsFolderPath();
EditorTools.ClearFolder(streamingFolderPath);
}
/// <summary>
@@ -40,17 +48,17 @@ namespace YooAsset.Editor
/// </summary>
public static void DeleteStreamingAssetsIgnoreFiles()
{
string streamingPath = Application.dataPath + "/StreamingAssets";
if (Directory.Exists(streamingPath))
string streamingFolderPath = GetStreamingAssetsFolderPath();
if (Directory.Exists(streamingFolderPath))
{
string[] files = Directory.GetFiles(streamingPath, "*.manifest", SearchOption.AllDirectories);
string[] files = Directory.GetFiles(streamingFolderPath, "*.manifest", SearchOption.AllDirectories);
foreach (var file in files)
{
FileInfo info = new FileInfo(file);
info.Delete();
}
files = Directory.GetFiles(streamingPath, "*.meta", SearchOption.AllDirectories);
files = Directory.GetFiles(streamingFolderPath, "*.meta", SearchOption.AllDirectories);
foreach (var item in files)
{
FileInfo info = new FileInfo(item);
@@ -109,11 +117,11 @@ namespace YooAsset.Editor
/// <summary>
/// 从输出目录加载补丁清单文件
/// 加载补丁清单文件
/// </summary>
internal static PatchManifest LoadPatchManifestFile(string fileDirectory)
internal static PatchManifest LoadPatchManifestFile(string fileDirectory, int resourceVersion)
{
string filePath = $"{fileDirectory}/{YooAssetSettingsData.Setting.PatchManifestFileName}";
string filePath = $"{fileDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(resourceVersion)}";
if (File.Exists(filePath) == false)
{
throw new System.Exception($"Not found patch manifest file : {filePath}");
@@ -122,5 +130,16 @@ namespace YooAsset.Editor
string jsonData = FileUtility.ReadFile(filePath);
return PatchManifest.Deserialize(jsonData);
}
/// <summary>
/// 获取旧的补丁清单
/// </summary>
internal static PatchManifest GetOldPatchManifest(string pipelineOutputDirectory)
{
string staticVersionFilePath = $"{pipelineOutputDirectory}/{YooAssetSettings.VersionFileName}";
string staticVersionContent = FileUtility.ReadFile(staticVersionFilePath);
int staticVersion = int.Parse(staticVersionContent);
return LoadPatchManifestFile(pipelineOutputDirectory, staticVersion);
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using UnityEngine;
namespace YooAsset.Editor
{
public class AssetBundleBuilderSetting : ScriptableObject
{
/// <summary>
/// 构建版本号
/// </summary>
public int BuildVersion = 0;
/// <summary>
/// 压缩方式
/// </summary>
public ECompressOption CompressOption = ECompressOption.LZ4;
/// <summary>
/// 加密类名称
/// </summary>
public string EncyptionClassName = string.Empty;
/// <summary>
/// 附加后缀格式
/// </summary>
public bool AppendExtension = false;
/// <summary>
/// 强制构建
/// </summary>
public bool ForceRebuild = false;
/// <summary>
/// 内置标签
/// </summary>
public string BuildTags = string.Empty;
}
}

View File

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

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace YooAsset.Editor
{
public class AssetBundleBuilderSettingData
{
private static AssetBundleBuilderSetting _setting = null;
public static AssetBundleBuilderSetting Setting
{
get
{
if (_setting == null)
LoadSettingData();
return _setting;
}
}
/// <summary>
/// 加载配置文件
/// </summary>
private static void LoadSettingData()
{
// 加载配置文件
_setting = AssetDatabase.LoadAssetAtPath<AssetBundleBuilderSetting>(EditorDefine.AssetBundleBuilderSettingFilePath);
if (_setting == null)
{
Debug.LogWarning($"Create new {nameof(AssetBundleBuilderSetting)}.asset : {EditorDefine.AssetBundleBuilderSettingFilePath}");
_setting = ScriptableObject.CreateInstance<AssetBundleBuilderSetting>();
EditorTools.CreateFileDirectory(EditorDefine.AssetBundleBuilderSettingFilePath);
AssetDatabase.CreateAsset(Setting, EditorDefine.AssetBundleBuilderSettingFilePath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
else
{
Debug.Log($"Load {nameof(AssetBundleBuilderSetting)}.asset ok");
}
}
/// <summary>
/// 存储文件
/// </summary>
public static void SaveFile()
{
if (Setting != null)
{
EditorUtility.SetDirty(Setting);
AssetDatabase.SaveAssets();
Debug.Log($"{nameof(AssetBundleBuilderSetting)}.asset is saved!");
}
}
}
}

View File

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

View File

@@ -61,23 +61,43 @@ namespace YooAsset.Editor
_buildOutputTxt.SetEnabled(false);
// 构建版本
var appVersion = new Version(Application.version);
_buildVersionField = root.Q<IntegerField>("BuildVersion");
_buildVersionField.SetValueWithoutNotify(appVersion.Revision);
_buildVersionField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.BuildVersion);
_buildVersionField.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSettingData.Setting.BuildVersion = _buildVersionField.value;
});
// 压缩方式
_compressionField = root.Q<EnumField>("Compression");
_compressionField.Init(ECompressOption.LZ4);
_compressionField.SetValueWithoutNotify(ECompressOption.LZ4);
_compressionField.Init(AssetBundleBuilderSettingData.Setting.CompressOption);
_compressionField.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.CompressOption);
_compressionField.style.width = 300;
_compressionField.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSettingData.Setting.CompressOption = (ECompressOption)_compressionField.value;
});
// 加密方法
var encryptionContainer = root.Q("EncryptionContainer");
if (_encryptionServicesClassNames.Count > 0)
{
_encryptionField = new PopupField<string>(_encryptionServicesClassNames, 0);
int defaultIndex = 0;
for (int index = 0; index < _encryptionServicesClassNames.Count; index++)
{
if (_encryptionServicesClassNames[index] == AssetBundleBuilderSettingData.Setting.EncyptionClassName)
{
defaultIndex = index;
break;
}
}
_encryptionField = new PopupField<string>(_encryptionServicesClassNames, defaultIndex);
_encryptionField.label = "Encryption";
_encryptionField.style.width = 300;
_encryptionField.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSettingData.Setting.EncyptionClassName = _encryptionField.value;
});
encryptionContainer.Add(_encryptionField);
}
else
@@ -90,18 +110,29 @@ namespace YooAsset.Editor
// 附加后缀格式
_appendExtensionToggle = root.Q<Toggle>("AppendExtension");
_appendExtensionToggle.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.AppendExtension);
_appendExtensionToggle.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSettingData.Setting.AppendExtension = _appendExtensionToggle.value;
});
// 强制构建
_forceRebuildToggle = root.Q<Toggle>("ForceRebuild");
_forceRebuildToggle.SetValueWithoutNotify(true);
_forceRebuildToggle.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.ForceRebuild);
_forceRebuildToggle.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSettingData.Setting.ForceRebuild = _forceRebuildToggle.value;
_buildTagsTxt.SetEnabled(_forceRebuildToggle.value);
});
// 内置标签
_buildTagsTxt = root.Q<TextField>("BuildinTags");
_buildTagsTxt.SetEnabled(_forceRebuildToggle.value);
_buildTagsTxt.SetValueWithoutNotify(AssetBundleBuilderSettingData.Setting.BuildTags);
_buildTagsTxt.RegisterValueChangedCallback(evt =>
{
AssetBundleBuilderSettingData.Setting.BuildTags = _buildTagsTxt.value;
});
// 构建按钮
var buildButton = root.Q<Button>("Build");
@@ -112,6 +143,10 @@ namespace YooAsset.Editor
Debug.LogError(e.ToString());
}
}
public void OnDestroy()
{
AssetBundleBuilderSettingData.SaveFile();
}
private void BuildButton_clicked()
{

View File

@@ -31,6 +31,11 @@ namespace YooAsset.Editor
/// </summary>
public bool IsCollectAsset { private set; get; }
/// <summary>
/// 是否为着色器资源
/// </summary>
public bool IsShaderAsset { private set; get; }
/// <summary>
/// 被依赖次数
/// </summary>
@@ -54,6 +59,12 @@ namespace YooAsset.Editor
IsRawAsset = isRawAsset;
NotWriteToAssetList = notWriteToAssetList;
IsCollectAsset = true;
System.Type assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
IsShaderAsset = true;
else
IsShaderAsset = false;
}
public BuildAssetInfo(string assetPath)
{
@@ -61,6 +72,12 @@ namespace YooAsset.Editor
IsRawAsset = false;
NotWriteToAssetList = true;
IsCollectAsset = false;
System.Type assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
IsShaderAsset = true;
else
IsShaderAsset = false;
}
/// <summary>
@@ -82,7 +99,7 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(BundleName) == false)
throw new System.Exception("Should never get here !");
BundleName = bundleName;
BundleName = bundleName;
}
/// <summary>
@@ -99,7 +116,7 @@ namespace YooAsset.Editor
/// <summary>
/// 添加资源分类标签
/// </summary>
public void AddAssetTag(string tag)
public void AddAssetTag(string tag)
{
if (AssetTags.Contains(tag) == false)
{

View File

@@ -89,10 +89,7 @@ namespace YooAsset.Editor
/// </summary>
public string GetAppendExtension()
{
if (IsRawFile)
return $".{YooAssetSettingsData.Setting.RawFileVariant}";
else
return $".{YooAssetSettingsData.Setting.AssetBundleFileVariant}";
return System.IO.Path.GetExtension(BundleName);
}
/// <summary>

View File

@@ -26,7 +26,7 @@ namespace YooAsset.Editor
{
if (buildAssetDic.ContainsKey(collectAssetInfo.AssetPath) == false)
{
var buildAssetInfo = new BuildAssetInfo(collectAssetInfo.AssetPath, collectAssetInfo.IsRawAsset, collectAssetInfo.NotWriteToAssetList);
var buildAssetInfo = new BuildAssetInfo(collectAssetInfo.AssetPath, collectAssetInfo.IsRawAsset, collectAssetInfo.NotWriteToAssetList);
buildAssetInfo.SetBundleName(collectAssetInfo.BundleName);
buildAssetInfo.AddAssetTags(collectAssetInfo.AssetTags);
buildAssetDic.Add(collectAssetInfo.AssetPath, buildAssetInfo);
@@ -78,6 +78,13 @@ namespace YooAsset.Editor
var buildAssetInfo = pair.Value;
if (buildAssetInfo.IsCollectAsset)
continue;
if (AssetBundleGrouperSettingData.Setting.AutoCollectShaders)
{
if (buildAssetInfo.IsShaderAsset)
continue;
}
if (buildAssetInfo.DependCount == 0)
removeList.Add(buildAssetInfo);
}
@@ -93,9 +100,17 @@ namespace YooAsset.Editor
var buildAssetInfo = pair.Value;
if (buildAssetInfo.BundleNameIsValid() == false)
{
string bundleName = defaultPackRule.GetBundleName(new PackRuleData(buildAssetInfo.AssetPath));
bundleName = AssetBundleCollector.RevisedBundleName(bundleName);
buildAssetInfo.SetBundleName(bundleName);
string shaderBundleName = AssetBundleCollector.CollectShaderBundleName(buildAssetInfo.AssetPath);
if (string.IsNullOrEmpty(shaderBundleName) == false)
{
buildAssetInfo.SetBundleName(shaderBundleName);
}
else
{
string bundleName = defaultPackRule.GetBundleName(new PackRuleData(buildAssetInfo.AssetPath));
bundleName = AssetBundleCollector.CorrectBundleName(bundleName, false);
buildAssetInfo.SetBundleName(bundleName);
}
}
}

View File

@@ -46,6 +46,11 @@ namespace YooAsset.Editor
public IEncryptionServices EncryptionServices;
/// <summary>
/// 演练构建模式
/// </summary>
public bool DryRunBuild;
/// <summary>
/// 强制重新构建整个项目如果为FALSE则是增量打包
/// </summary>

View File

@@ -27,11 +27,6 @@ namespace YooAsset.Editor
/// </summary>
public long SizeBytes;
/// <summary>
/// 文件版本
/// </summary>
public int Version;
/// <summary>
/// Tags
/// </summary>

View File

@@ -59,6 +59,7 @@ namespace YooAsset.Editor
public string EncryptionServicesClassName;
// 构建参数
public bool DryRunBuild;
public bool ForceRebuild;
public string BuildinTags;
public ECompressOption CompressOption;

View File

@@ -28,7 +28,8 @@ namespace YooAsset.Editor
}
catch (Exception e)
{
Debug.LogError($"Build task {task.GetType().Name} failed : {e}");
Debug.LogError($"Build task {task.GetType().Name} failed !");
Debug.LogError($"Detail error : {e}");
succeed = false;
break;
}

View File

@@ -31,164 +31,29 @@ namespace YooAsset.Editor
context.SetContextObject(unityManifestContext);
// 拷贝原生文件
if (buildParametersContext.Parameters.DryRunBuild == false)
{
CopyRawBundle(buildMapContext, buildParametersContext);
}
}
/// <summary>
/// 拷贝原生文件
/// </summary>
private void CopyRawBundle(BuildMapContext buildMapContext, AssetBundleBuilder.BuildParametersContext buildParametersContext)
{
foreach (var bundleInfo in buildMapContext.BundleInfos)
{
if (bundleInfo.IsRawFile)
{
string dest = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
foreach(var buildAsset in bundleInfo.BuildinAssets)
foreach (var buildAsset in bundleInfo.BuildinAssets)
{
if(buildAsset.IsRawAsset)
if (buildAsset.IsRawAsset)
EditorTools.CopyFile(buildAsset.AssetPath, dest, true);
}
}
}
// 验证构建结果
if (buildParametersContext.Parameters.VerifyBuildingResult)
{
VerifyingBuildingResult(context, unityManifest);
}
}
/// <summary>
/// 验证构建结果
/// </summary>
private void VerifyingBuildingResult(BuildContext context, AssetBundleManifest unityManifest)
{
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
string[] buildedBundles = unityManifest.GetAllAssetBundles();
// 1. 过滤掉原生Bundle
List<BuildBundleInfo> expectBundles = new List<BuildBundleInfo>(buildedBundles.Length);
foreach(var bundleInfo in buildMapContext.BundleInfos)
{
if (bundleInfo.IsRawFile == false)
expectBundles.Add(bundleInfo);
}
// 2. 验证数量
if (buildedBundles.Length != expectBundles.Count)
{
Debug.LogWarning($"构建过程中可能存在无效的资源导致和预期构建的Bundle数量不一致");
}
// 3. 正向验证Bundle
foreach (var bundleName in buildedBundles)
{
if (buildMapContext.IsContainsBundle(bundleName) == false)
{
throw new Exception($"Should never get here !");
}
}
// 4. 反向验证Bundle
bool isPass = true;
foreach (var expectBundle in expectBundles)
{
bool isMatch = false;
foreach (var buildedBundle in buildedBundles)
{
if (buildedBundle == expectBundle.BundleName)
{
isMatch = true;
break;
}
}
if (isMatch == false)
{
isPass = false;
Debug.LogWarning($"没有找到预期构建的Bundle文件 : {expectBundle.BundleName}");
}
}
if(isPass == false)
{
throw new Exception("构建结果验证没有通过,请参考警告日志!");
}
// 5. 验证Asset
int progressValue = 0;
foreach (var buildedBundle in buildedBundles)
{
string filePath = $"{buildParameters.PipelineOutputDirectory}/{buildedBundle}";
string[] allBuildinAssetPaths = GetAssetBundleAllAssets(filePath);
string[] expectBuildinAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
if (expectBuildinAssetPaths.Length != allBuildinAssetPaths.Length)
{
Debug.LogWarning($"构建的Bundle文件内的资源对象数量和预期不匹配 : {buildedBundle}");
isPass = false;
continue;
}
foreach (var buildinAssetPath in allBuildinAssetPaths)
{
var guid = AssetDatabase.AssetPathToGUID(buildinAssetPath);
if (string.IsNullOrEmpty(guid))
{
Debug.LogWarning($"无效的资源路径,请检查路径是否带有特殊符号或中文:{buildinAssetPath}");
isPass = false;
continue;
}
bool isMatch = false;
foreach (var exceptBuildAssetPath in expectBuildinAssetPaths)
{
var guidExcept = AssetDatabase.AssetPathToGUID(exceptBuildAssetPath);
if (guid == guidExcept)
{
isMatch = true;
break;
}
}
if (isMatch == false)
{
Debug.LogWarning($"在构建的Bundle文件里发现了没有匹配的资源对象{buildinAssetPath}");
isPass = false;
continue;
}
}
EditorTools.DisplayProgressBar("验证构建结果", ++progressValue, buildedBundles.Length);
}
EditorTools.ClearProgressBar();
if (isPass == false)
{
throw new Exception("构建结果验证没有通过,请参考警告日志!");
}
// 卸载所有加载的Bundle
Debug.Log("构建结果验证成功!");
}
/// <summary>
/// 解析.manifest文件并获取资源列表
/// </summary>
private string[] GetAssetBundleAllAssets(string filePath)
{
string manifestFilePath = $"{filePath}.manifest";
List<string> assetLines = new List<string>();
using (StreamReader reader = File.OpenText(manifestFilePath))
{
string content;
bool findTarget = false;
while (null != (content = reader.ReadLine()))
{
if (content.StartsWith("Dependencies:"))
break;
if (findTarget == false && content.StartsWith("Assets:"))
findTarget = true;
if (findTarget)
{
if (content.StartsWith("- "))
{
string assetPath = content.TrimStart("- ".ToCharArray());
assetLines.Add(assetPath);
}
}
}
}
return assetLines.ToArray();
}
}
}

View File

@@ -15,21 +15,20 @@ namespace YooAsset.Editor
{
// 注意:我们只有在强制重建的时候才会拷贝
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
if(buildParameters.Parameters.ForceRebuild)
if (buildParameters.Parameters.DryRunBuild == false && buildParameters.Parameters.ForceRebuild)
{
// 清空流目录
AssetBundleBuilderHelper.ClearStreamingAssetsFolder();
// 拷贝内置文件
var pipelineOutputDirectory = buildParameters.PipelineOutputDirectory;
CopyBuildinFilesToStreaming(pipelineOutputDirectory);
CopyBuildinFilesToStreaming(buildParameters.PipelineOutputDirectory, buildParameters.Parameters.BuildVersion);
}
}
private void CopyBuildinFilesToStreaming(string pipelineOutputDirectory)
private void CopyBuildinFilesToStreaming(string pipelineOutputDirectory, int buildVersion)
{
// 加载补丁清单
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(pipelineOutputDirectory);
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(pipelineOutputDirectory, buildVersion);
// 拷贝文件列表
foreach (var patchBundle in patchManifest.BundleList)
@@ -38,22 +37,29 @@ namespace YooAsset.Editor
continue;
string sourcePath = $"{pipelineOutputDirectory}/{patchBundle.BundleName}";
string destPath = $"{Application.dataPath}/StreamingAssets/{patchBundle.Hash}";
string destPath = $"{AssetBundleBuilderHelper.GetStreamingAssetsFolderPath()}/{patchBundle.Hash}";
Debug.Log($"拷贝内置文件到流目录:{patchBundle.BundleName}");
EditorTools.CopyFile(sourcePath, destPath, true);
}
// 拷贝清单文件
{
string sourcePath = $"{pipelineOutputDirectory}/{YooAssetSettingsData.Setting.PatchManifestFileName}";
string destPath = $"{Application.dataPath}/StreamingAssets/{YooAssetSettingsData.Setting.PatchManifestFileName}";
string sourcePath = $"{pipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(buildVersion)}";
string destPath = $"{AssetBundleBuilderHelper.GetStreamingAssetsFolderPath()}/{YooAssetSettingsData.GetPatchManifestFileName(buildVersion)}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
// 拷贝清单哈希文件
{
string sourcePath = $"{pipelineOutputDirectory}/{YooAssetSettingsData.Setting.PatchManifestHashFileName}";
string destPath = $"{Application.dataPath}/StreamingAssets/{YooAssetSettingsData.Setting.PatchManifestHashFileName}";
string sourcePath = $"{pipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestHashFileName(buildVersion)}";
string destPath = $"{AssetBundleBuilderHelper.GetStreamingAssetsFolderPath()}/{YooAssetSettingsData.GetPatchManifestHashFileName(buildVersion)}";
EditorTools.CopyFile(sourcePath, destPath, true);
}
// 拷贝静态版本文件
{
string sourcePath = $"{pipelineOutputDirectory}/{YooAssetSettings.VersionFileName}";
string destPath = $"{AssetBundleBuilderHelper.GetStreamingAssetsFolderPath()}/{YooAssetSettings.VersionFileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
}

View File

@@ -24,6 +24,8 @@ namespace YooAsset.Editor
private void CreatePatchManifestFile(AssetBundleBuilder.BuildParametersContext buildParameters,
BuildMapContext buildMapContext, TaskEncryption.EncryptionContext encryptionContext)
{
int resourceVersion = buildParameters.Parameters.BuildVersion;
// 创建新补丁清单
PatchManifest patchManifest = new PatchManifest();
patchManifest.ResourceVersion = buildParameters.Parameters.BuildVersion;
@@ -32,15 +34,21 @@ namespace YooAsset.Editor
patchManifest.AssetList = GetAllPatchAsset(buildMapContext, patchManifest);
// 创建补丁清单文件
string manifestFilePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.Setting.PatchManifestFileName}";
string manifestFilePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(resourceVersion)}";
UnityEngine.Debug.Log($"创建补丁清单文件:{manifestFilePath}");
PatchManifest.Serialize(manifestFilePath, patchManifest);
// 创建补丁清单哈希文件
string manifestHashFilePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.Setting.PatchManifestHashFileName}";
string manifestHashFilePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestHashFileName(resourceVersion)}";
string manifestHash = HashUtility.FileMD5(manifestFilePath);
UnityEngine.Debug.Log($"创建补丁清单哈希文件:{manifestHashFilePath}");
FileUtility.CreateFile(manifestHashFilePath, manifestHash);
// 创建静态版本文件
string staticVersionFilePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettings.VersionFileName}";
string staticVersion = resourceVersion.ToString();
UnityEngine.Debug.Log($"创建静态版本文件:{staticVersionFilePath}");
FileUtility.CreateFile(staticVersionFilePath, staticVersion);
}
/// <summary>
@@ -54,21 +62,14 @@ namespace YooAsset.Editor
// 内置标记列表
List<string> buildinTags = buildParameters.Parameters.GetBuildinTags();
// 加载旧补丁清单
PatchManifest oldPatchManifest = null;
if (buildParameters.Parameters.ForceRebuild == false)
{
oldPatchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
}
bool dryRunBuild = buildParameters.Parameters.DryRunBuild;
foreach (var bundleInfo in buildMapContext.BundleInfos)
{
var bundleName = bundleInfo.BundleName;
string filePath = $"{buildParameters.PipelineOutputDirectory}/{bundleName}";
string hash = HashUtility.FileMD5(filePath);
string crc = HashUtility.FileCRC32(filePath);
long size = FileUtility.GetFileSize(filePath);
int version = buildParameters.Parameters.BuildVersion;
string hash = GetFileHash(filePath, dryRunBuild);
string crc32 = GetFileCRC(filePath, dryRunBuild);
long size = GetFileSize(filePath, dryRunBuild);
string[] tags = buildMapContext.GetAssetTags(bundleName);
bool isEncrypted = encryptionContext.IsEncryptFile(bundleName);
bool isBuildin = IsBuildinBundle(tags, buildinTags);
@@ -80,14 +81,7 @@ namespace YooAsset.Editor
hash += bundleInfo.GetAppendExtension();
}
// 注意:如果文件没有变化使用旧版本号
if (oldPatchManifest != null && oldPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle value))
{
if (value.Hash == hash)
version = value.Version;
}
PatchBundle patchBundle = new PatchBundle(bundleName, hash, crc, size, version, tags);
PatchBundle patchBundle = new PatchBundle(bundleName, hash, crc32, size, tags);
patchBundle.SetFlagsValue(isEncrypted, isBuildin, isRawFile);
result.Add(patchBundle);
}
@@ -107,6 +101,27 @@ namespace YooAsset.Editor
}
return false;
}
private string GetFileHash(string filePath, bool dryRunBuild)
{
if (dryRunBuild)
return "00000000000000000000000000000000"; //32位
else
return HashUtility.FileMD5(filePath);
}
private string GetFileCRC(string filePath, bool dryRunBuild)
{
if (dryRunBuild)
return "00000000"; //8位
else
return HashUtility.FileCRC32(filePath);
}
private long GetFileSize(string filePath, bool dryRunBuild)
{
if (dryRunBuild)
return 0;
else
return FileUtility.GetFileSize(filePath);
}
/// <summary>
/// 获取资源列表
@@ -122,13 +137,13 @@ namespace YooAsset.Editor
PatchAsset patchAsset = new PatchAsset();
patchAsset.AssetPath = assetInfo.AssetPath;
patchAsset.BundleID = GetAssetBundleID(assetInfo.BundleName, patchManifest);
patchAsset.DependIDs = GetAssetBundleDependIDs(assetInfo, patchManifest);
patchAsset.DependIDs = GetAssetBundleDependIDs(patchAsset.BundleID, assetInfo, patchManifest);
result.Add(patchAsset);
}
}
return result;
}
private int[] GetAssetBundleDependIDs(BuildAssetInfo assetInfo, PatchManifest patchManifest)
private int[] GetAssetBundleDependIDs(int mainBundleID, BuildAssetInfo assetInfo, PatchManifest patchManifest)
{
List<int> result = new List<int>();
foreach (var dependAssetInfo in assetInfo.AllDependAssetInfos)
@@ -136,8 +151,11 @@ namespace YooAsset.Editor
if (dependAssetInfo.BundleNameIsValid() == false)
continue;
int bundleID = GetAssetBundleID(dependAssetInfo.BundleName, patchManifest);
if (result.Contains(bundleID) == false)
result.Add(bundleID);
if (mainBundleID != bundleID)
{
if (result.Contains(bundleID) == false)
result.Add(bundleID);
}
}
return result.ToArray();
}

View File

@@ -11,7 +11,10 @@ namespace YooAsset.Editor
void IBuildTask.Run(BuildContext context)
{
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
CopyPatchFiles(buildParameters);
if (buildParameters.Parameters.DryRunBuild == false)
{
CopyPatchFiles(buildParameters);
}
}
/// <summary>
@@ -19,31 +22,40 @@ namespace YooAsset.Editor
/// </summary>
private void CopyPatchFiles(AssetBundleBuilder.BuildParametersContext buildParameters)
{
int resourceVersion = buildParameters.Parameters.BuildVersion;
string packageDirectory = buildParameters.GetPackageDirectory();
UnityEngine.Debug.Log($"开始拷贝补丁文件到补丁包目录:{packageDirectory}");
UnityEngine.Debug.Log($"准备开始拷贝补丁文件到补丁包目录:{packageDirectory}");
// 拷贝Report文件
{
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettings.ReportFileName}";
string destPath = $"{packageDirectory}/{YooAssetSettings.ReportFileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
UnityEngine.Debug.Log($"拷贝Report文件到:{destPath}");
UnityEngine.Debug.Log($"拷贝构建报告文件到:{destPath}");
}
// 拷贝PatchManifest文件
// 拷贝补丁清单文件
{
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.Setting.PatchManifestFileName}";
string destPath = $"{packageDirectory}/{YooAssetSettingsData.Setting.PatchManifestFileName}";
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(resourceVersion)}";
string destPath = $"{packageDirectory}/{YooAssetSettingsData.GetPatchManifestFileName(resourceVersion)}";
EditorTools.CopyFile(sourcePath, destPath, true);
UnityEngine.Debug.Log($"拷贝PatchManifest文件到:{destPath}");
UnityEngine.Debug.Log($"拷贝补丁清单文件到:{destPath}");
}
// 拷贝PatchManifest哈希文件
// 拷贝补丁清单哈希文件
{
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.Setting.PatchManifestHashFileName}";
string destPath = $"{packageDirectory}/{YooAssetSettingsData.Setting.PatchManifestHashFileName}";
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetPatchManifestHashFileName(resourceVersion)}";
string destPath = $"{packageDirectory}/{YooAssetSettingsData.GetPatchManifestHashFileName(resourceVersion)}";
EditorTools.CopyFile(sourcePath, destPath, true);
UnityEngine.Debug.Log($"拷贝PatchManifest哈希文件到:{destPath}");
UnityEngine.Debug.Log($"拷贝补丁清单哈希文件到:{destPath}");
}
// 拷贝静态版本文件
{
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettings.VersionFileName}";
string destPath = $"{packageDirectory}/{YooAssetSettings.VersionFileName}";
EditorTools.CopyFile(sourcePath, destPath, true);
UnityEngine.Debug.Log($"拷贝静态版本文件到:{destPath}");
}
// 拷贝UnityManifest序列化文件
@@ -62,20 +74,16 @@ namespace YooAsset.Editor
}
// 拷贝所有补丁文件
// 注意:拷贝的补丁文件都是需要玩家热更新的文件
int progressValue = 0;
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory, buildParameters.Parameters.BuildVersion);
int patchFileTotalCount = patchManifest.BundleList.Count;
foreach (var patchBundle in patchManifest.BundleList)
{
if (patchBundle.Version == buildParameters.Parameters.BuildVersion)
{
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{patchBundle.BundleName}";
string destPath = $"{packageDirectory}/{patchBundle.Hash}";
EditorTools.CopyFile(sourcePath, destPath, true);
UnityEngine.Debug.Log($"拷贝补丁文件到补丁包:{patchBundle.BundleName}");
EditorTools.DisplayProgressBar("拷贝补丁文件", ++progressValue, patchFileTotalCount);
}
string sourcePath = $"{buildParameters.PipelineOutputDirectory}/{patchBundle.BundleName}";
string destPath = $"{packageDirectory}/{patchBundle.Hash}";
EditorTools.CopyFile(sourcePath, destPath, true);
UnityEngine.Debug.Log($"拷贝补丁文件到补丁包:{patchBundle.BundleName}");
EditorTools.DisplayProgressBar("拷贝补丁文件", ++progressValue, patchFileTotalCount);
}
EditorTools.ClearProgressBar();
}

View File

@@ -18,7 +18,7 @@ namespace YooAsset.Editor
private void CreateReportFile(AssetBundleBuilder.BuildParametersContext buildParameters, BuildMapContext buildMapContext)
{
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory, buildParameters.Parameters.BuildVersion);
BuildReport buildReport = new BuildReport();
buildParameters.StopWatch();
@@ -35,8 +35,9 @@ namespace YooAsset.Editor
buildReport.Summary.ShadersBundleName = AssetBundleGrouperSettingData.Setting.ShadersBundleName;
buildReport.Summary.EncryptionServicesClassName = buildParameters.Parameters.EncryptionServices == null ?
"null" : buildParameters.Parameters.EncryptionServices.GetType().FullName;
// 构建参数
buildReport.Summary.DryRunBuild = buildParameters.Parameters.DryRunBuild;
buildReport.Summary.ForceRebuild = buildParameters.Parameters.ForceRebuild;
buildReport.Summary.BuildinTags = buildParameters.Parameters.BuildinTags;
buildReport.Summary.CompressOption = buildParameters.Parameters.CompressOption;
@@ -79,7 +80,6 @@ namespace YooAsset.Editor
reportBundleInfo.Hash = patchBundle.Hash;
reportBundleInfo.CRC = patchBundle.CRC;
reportBundleInfo.SizeBytes = patchBundle.SizeBytes;
reportBundleInfo.Version = patchBundle.Version;
reportBundleInfo.Tags = patchBundle.Tags;
reportBundleInfo.Flags = patchBundle.Flags;
buildReport.BundleInfos.Add(reportBundleInfo);

View File

@@ -26,9 +26,18 @@ namespace YooAsset.Editor
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
EncryptionContext encryptionContext = new EncryptionContext();
encryptionContext.EncryptList = EncryptFiles(buildParameters, buildMapContext);
context.SetContextObject(encryptionContext);
if (buildParameters.Parameters.DryRunBuild)
{
EncryptionContext encryptionContext = new EncryptionContext();
encryptionContext.EncryptList = new List<string>();
context.SetContextObject(encryptionContext);
}
else
{
EncryptionContext encryptionContext = new EncryptionContext();
encryptionContext.EncryptList = EncryptFiles(buildParameters, buildMapContext);
context.SetContextObject(encryptionContext);
}
}
/// <summary>

View File

@@ -43,7 +43,7 @@ namespace YooAsset.Editor
throw new Exception($"补丁包已经存在:{packageDirectory}");
// 检测内置资源分类标签是否一致
PatchManifest oldPatchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory);
var oldPatchManifest = AssetBundleBuilderHelper.GetOldPatchManifest(buildParameters.PipelineOutputDirectory);
if (buildParameters.Parameters.BuildinTags != oldPatchManifest.BuildinTags)
throw new Exception($"增量更新时内置资源标签必须一致:{buildParameters.Parameters.BuildinTags} != {oldPatchManifest.BuildinTags}");
}

View File

@@ -0,0 +1,168 @@
using System;
using System.Linq;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
public class TaskVerifyBuildResult : IBuildTask
{
void IBuildTask.Run(BuildContext context)
{
var buildParametersContext = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
var unityManifestContext = context.GetContextObject<TaskBuilding.UnityManifestContext>();
// 验证构建结果
if (buildParametersContext.Parameters.VerifyBuildingResult)
{
VerifyingBuildingResult(context, unityManifestContext.UnityManifest);
}
}
/// <summary>
/// 验证构建结果
/// </summary>
private void VerifyingBuildingResult(BuildContext context, AssetBundleManifest unityManifest)
{
var buildParameters = context.GetContextObject<AssetBundleBuilder.BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
string[] buildedBundles = unityManifest.GetAllAssetBundles();
// 1. 过滤掉原生Bundle
List<BuildBundleInfo> expectBundles = new List<BuildBundleInfo>(buildedBundles.Length);
foreach(var bundleInfo in buildMapContext.BundleInfos)
{
if (bundleInfo.IsRawFile == false)
expectBundles.Add(bundleInfo);
}
// 2. 验证数量
if (buildedBundles.Length != expectBundles.Count)
{
Debug.LogWarning($"构建过程中可能存在无效的资源导致和预期构建的Bundle数量不一致");
}
// 3. 正向验证Bundle
foreach (var bundleName in buildedBundles)
{
if (buildMapContext.IsContainsBundle(bundleName) == false)
{
throw new Exception($"Should never get here !");
}
}
// 4. 反向验证Bundle
bool isPass = true;
foreach (var expectBundle in expectBundles)
{
bool isMatch = false;
foreach (var buildedBundle in buildedBundles)
{
if (buildedBundle == expectBundle.BundleName)
{
isMatch = true;
break;
}
}
if (isMatch == false)
{
isPass = false;
Debug.LogWarning($"没有找到预期构建的Bundle文件 : {expectBundle.BundleName}");
}
}
if(isPass == false)
{
throw new Exception("构建结果验证没有通过,请参考警告日志!");
}
// 5. 验证Asset
if(buildParameters.Parameters.DryRunBuild == false)
{
int progressValue = 0;
foreach (var buildedBundle in buildedBundles)
{
string filePath = $"{buildParameters.PipelineOutputDirectory}/{buildedBundle}";
string[] allBuildinAssetPaths = GetAssetBundleAllAssets(filePath);
string[] expectBuildinAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
if (expectBuildinAssetPaths.Length != allBuildinAssetPaths.Length)
{
Debug.LogWarning($"构建的Bundle文件内的资源对象数量和预期不匹配 : {buildedBundle}");
isPass = false;
continue;
}
foreach (var buildinAssetPath in allBuildinAssetPaths)
{
var guid = AssetDatabase.AssetPathToGUID(buildinAssetPath);
if (string.IsNullOrEmpty(guid))
{
Debug.LogWarning($"无效的资源路径,请检查路径是否带有特殊符号或中文:{buildinAssetPath}");
isPass = false;
continue;
}
bool isMatch = false;
foreach (var exceptBuildAssetPath in expectBuildinAssetPaths)
{
var guidExcept = AssetDatabase.AssetPathToGUID(exceptBuildAssetPath);
if (guid == guidExcept)
{
isMatch = true;
break;
}
}
if (isMatch == false)
{
Debug.LogWarning($"在构建的Bundle文件里发现了没有匹配的资源对象{buildinAssetPath}");
isPass = false;
continue;
}
}
EditorTools.DisplayProgressBar("验证构建结果", ++progressValue, buildedBundles.Length);
}
EditorTools.ClearProgressBar();
if (isPass == false)
{
throw new Exception("构建结果验证没有通过,请参考警告日志!");
}
}
// 卸载所有加载的Bundle
Debug.Log("构建结果验证成功!");
}
/// <summary>
/// 解析.manifest文件并获取资源列表
/// </summary>
private string[] GetAssetBundleAllAssets(string filePath)
{
string manifestFilePath = $"{filePath}.manifest";
List<string> assetLines = new List<string>();
using (StreamReader reader = File.OpenText(manifestFilePath))
{
string content;
bool findTarget = false;
while (null != (content = reader.ReadLine()))
{
if (content.StartsWith("Dependencies:"))
break;
if (findTarget == false && content.StartsWith("Assets:"))
findTarget = true;
if (findTarget)
{
if (content.StartsWith("- "))
{
string assetPath = content.TrimStart("- ".ToCharArray());
assetLines.Add(assetPath);
}
}
}
}
return assetLines.ToArray();
}
}
}

View File

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

View File

@@ -114,7 +114,7 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
label.style.width = 150;
element.Add(label);
}
@@ -124,6 +124,26 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 150;
element.Add(label);
}
{
var label = new Label();
label.name = "Label4";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
element.Add(label);
}
{
var label = new Label();
label.name = "Label5";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 120;
element.Add(label);
}
@@ -139,9 +159,17 @@ namespace YooAsset.Editor
var label1 = element.Q<Label>("Label1");
label1.text = providerInfo.AssetPath;
// Ref Count
// Spawn Scene
var label2 = element.Q<Label>("Label2");
label2.text = providerInfo.RefCount.ToString();
label2.text = providerInfo.SpawnScene;
// Spawn Time
var label3 = element.Q<Label>("Label3");
label3.text = providerInfo.SpawnTime;
// Ref Count
var label4 = element.Q<Label>("Label4");
label4.text = providerInfo.RefCount.ToString();
// Status
StyleColor textColor;
@@ -149,9 +177,9 @@ namespace YooAsset.Editor
textColor = new StyleColor(Color.yellow);
else
textColor = label1.style.color;
var label3 = element.Q<Label>("Label3");
label3.text = providerInfo.Status.ToString();
label3.style.color = textColor;
var label5 = element.Q<Label>("Label5");
label5.text = providerInfo.Status.ToString();
label5.style.color = textColor;
}
private void AssetListView_onSelectionChange(IEnumerable<object> objs)
{
@@ -178,16 +206,6 @@ namespace YooAsset.Editor
element.Add(label);
}
{
var label = new Label();
label.name = "Label2";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
element.Add(label);
}
{
var label = new Label();
label.name = "Label3";
@@ -219,10 +237,6 @@ namespace YooAsset.Editor
var label1 = element.Q<Label>("Label1");
label1.text = bundleInfo.BundleName;
// Version
var label2 = element.Q<Label>("Label2");
label2.text = bundleInfo.Version.ToString();
// Ref Count
var label3 = element.Q<Label>("Label3");
label3.text = bundleInfo.RefCount.ToString();

View File

@@ -2,15 +2,16 @@
<ui:VisualElement name="TopGroup" style="flex-grow: 1; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 2px; margin-bottom: 1px; display: flex;">
<uie:Toolbar name="TopBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Asset Path" display-tooltip-when-elided="true" name="TopBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Ref Count" display-tooltip-when-elided="true" name="TopBar2" style="width: 100px; -unity-text-align: middle-left; flex-grow: 0;" />
<uie:ToolbarButton text="Status" display-tooltip-when-elided="true" name="TopBar3" style="width: 120px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Spawn Scene" display-tooltip-when-elided="true" name="TopBar2" style="width: 150px; -unity-text-align: middle-left; flex-grow: 0;" />
<uie:ToolbarButton text="Spawn Time" display-tooltip-when-elided="true" name="TopBar3" style="width: 150px; -unity-text-align: middle-left; flex-grow: 0;" />
<uie:ToolbarButton text="Ref Count" display-tooltip-when-elided="true" name="TopBar4" style="width: 100px; -unity-text-align: middle-left; flex-grow: 0;" />
<uie:ToolbarButton text="Status" display-tooltip-when-elided="true" name="TopBar5" style="width: 120px; -unity-text-align: middle-left;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="TopListView" item-height="18" style="flex-grow: 1;" />
</ui:VisualElement>
<ui:VisualElement name="BottomGroup" style="height: 200px; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 1px; margin-bottom: 1px; display: flex;">
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Depend Bundles" display-tooltip-when-elided="true" name="BottomBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Version" display-tooltip-when-elided="true" name="BottomBar2" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Ref Count" display-tooltip-when-elided="true" name="BottomBar3" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Status" display-tooltip-when-elided="true" name="BottomBar4" style="width: 120px; -unity-text-align: middle-left;" />
</uie:Toolbar>

View File

@@ -15,7 +15,7 @@ namespace YooAsset.Editor
private TemplateContainer _root;
private ListView _bundleListView;
private ListView _includeListView;
private ListView _usingListView;
private DebugReport _debugReport;
/// <summary>
@@ -35,7 +35,7 @@ namespace YooAsset.Editor
_root = _visualAsset.CloneTree();
_root.style.flexGrow = 1f;
// 资源列表
// 资源列表
_bundleListView = _root.Q<ListView>("TopListView");
_bundleListView.makeItem = MakeAssetListViewItem;
_bundleListView.bindItem = BindAssetListViewItem;
@@ -45,10 +45,10 @@ namespace YooAsset.Editor
#else
_bundleListView.onSelectionChanged += BundleListView_onSelectionChange;
#endif
// 依赖列表
_includeListView = _root.Q<ListView>("BottomListView");
_includeListView.makeItem = MakeIncludeListViewItem;
_includeListView.bindItem = BindIncludeListViewItem;
// 使用列表
_usingListView = _root.Q<ListView>("BottomListView");
_usingListView.makeItem = MakeIncludeListViewItem;
_usingListView.bindItem = BindIncludeListViewItem;
}
/// <summary>
@@ -62,20 +62,21 @@ namespace YooAsset.Editor
}
private List<DebugBundleInfo> FilterViewItems(DebugReport debugReport, string searchKeyWord)
{
var result = new List<DebugBundleInfo>(debugReport.ProviderInfos.Count);
Dictionary<string, DebugBundleInfo> result = new Dictionary<string, DebugBundleInfo>(debugReport.ProviderInfos.Count);
foreach (var providerInfo in debugReport.ProviderInfos)
{
foreach(var bundleInfo in providerInfo.BundleInfos)
foreach (var bundleInfo in providerInfo.BundleInfos)
{
if (string.IsNullOrEmpty(searchKeyWord) == false)
{
if (bundleInfo.BundleName.Contains(searchKeyWord) == false)
continue;
}
result.Add(bundleInfo);
if (result.ContainsKey(bundleInfo.BundleName) == false)
result.Add(bundleInfo.BundleName, bundleInfo);
}
}
return result;
return result.Values.ToList();
}
/// <summary>
@@ -94,7 +95,7 @@ namespace YooAsset.Editor
_root.RemoveFromHierarchy();
}
// 顶部列表相关
private VisualElement MakeAssetListViewItem()
{
@@ -111,16 +112,6 @@ namespace YooAsset.Editor
element.Add(label);
}
{
var label = new Label();
label.name = "Label2";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
element.Add(label);
}
{
var label = new Label();
label.name = "Label3";
@@ -152,17 +143,13 @@ namespace YooAsset.Editor
var label1 = element.Q<Label>("Label1");
label1.text = bundleInfo.BundleName;
// Version
var label2 = element.Q<Label>("Label2");
label2.text = bundleInfo.Version.ToString();
// Ref Count
var label3 = element.Q<Label>("Label3");
label3.text = bundleInfo.RefCount.ToString();
// Status
StyleColor textColor;
if (bundleInfo.Status == AssetBundleLoader.EStatus.Fail)
if (bundleInfo.Status == AssetBundleLoaderBase.EStatus.Failed)
textColor = new StyleColor(Color.yellow);
else
textColor = label1.style.color;
@@ -175,7 +162,7 @@ namespace YooAsset.Editor
foreach (var item in objs)
{
DebugBundleInfo bundleInfo = item as DebugBundleInfo;
FillIncludeListView(bundleInfo);
FillUsingListView(bundleInfo.BundleName);
}
}
@@ -201,7 +188,7 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
label.style.width = 150;
element.Add(label);
}
@@ -211,41 +198,75 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 150;
element.Add(label);
}
{
var label = new Label();
label.name = "Label4";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
element.Add(label);
}
{
var label = new Label();
label.name = "Label5";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 120;
element.Add(label);
}
return element;
}
private void BindIncludeListViewItem(VisualElement element, int index)
{
List<DebugProviderInfo> providers = _includeListView.itemsSource as List<DebugProviderInfo>;
List<DebugProviderInfo> providers = _usingListView.itemsSource as List<DebugProviderInfo>;
DebugProviderInfo providerInfo = providers[index];
// Asset Path
var label1 = element.Q<Label>("Label1");
label1.text = providerInfo.AssetPath;
// Ref Count
// Spawn Scene
var label2 = element.Q<Label>("Label2");
label2.text = providerInfo.RefCount.ToString();
label2.text = providerInfo.SpawnScene;
// Spawn Time
var label3 = element.Q<Label>("Label3");
label3.text = providerInfo.SpawnTime;
// Ref Count
var label4 = element.Q<Label>("Label4");
label4.text = providerInfo.RefCount.ToString();
// Status
var label3 = element.Q<Label>("Label3");
label3.text = providerInfo.Status.ToString();
var label5 = element.Q<Label>("Label5");
label5.text = providerInfo.Status.ToString();
}
private void FillIncludeListView(DebugBundleInfo bundleInfo)
private void FillUsingListView(string bundleName)
{
_includeListView.Clear();
_includeListView.ClearSelection();
_usingListView.Clear();
_usingListView.ClearSelection();
List<DebugProviderInfo> source = new List<DebugProviderInfo>();
foreach(var providerInfo in _debugReport.ProviderInfos)
List<DebugProviderInfo> source = new List<DebugProviderInfo>();
foreach (var providerInfo in _debugReport.ProviderInfos)
{
if (providerInfo.BundleInfos.Contains(bundleInfo))
source.Add(providerInfo);
foreach (var bundleInfo in providerInfo.BundleInfos)
{
if (bundleInfo.BundleName == bundleName)
{
source.Add(providerInfo);
continue;
}
}
}
_includeListView.itemsSource = source;
_usingListView.itemsSource = source;
}
}
}

View File

@@ -2,7 +2,6 @@
<ui:VisualElement name="TopGroup" style="flex-grow: 1; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 2px; margin-bottom: 1px; display: flex;">
<uie:Toolbar name="TopBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Bundle Name" display-tooltip-when-elided="true" name="TopBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Version" display-tooltip-when-elided="true" name="TopBar2" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Ref Count" display-tooltip-when-elided="true" name="TopBar3" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Status" display-tooltip-when-elided="true" name="TopBar4" style="width: 120px; -unity-text-align: middle-left;" />
</uie:Toolbar>
@@ -11,8 +10,10 @@
<ui:VisualElement name="BottomGroup" style="height: 200px; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 1px; margin-bottom: 1px; display: flex;">
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Using Assets" display-tooltip-when-elided="true" name="BottomBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Ref Count" display-tooltip-when-elided="true" name="BottomBar3" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Status" display-tooltip-when-elided="true" name="BottomBar4" style="width: 120px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Spawn Scene" display-tooltip-when-elided="true" name="BottomBar2" style="width: 150px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Spawn Time" display-tooltip-when-elided="true" name="BottomBar3" style="width: 150px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Ref Count" display-tooltip-when-elided="true" name="BottomBar4" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Status" display-tooltip-when-elided="true" name="BottomBar5" style="width: 120px; -unity-text-align: middle-left;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="BottomListView" item-height="18" style="flex-grow: 1;" />
</ui:VisualElement>

View File

@@ -71,7 +71,7 @@ namespace YooAsset.Editor
continue;
if (result.ContainsKey(assetPath) == false)
{
string bundleName = GetBundleName(grouper, assetPath);
string bundleName = GetBundleName(grouper, assetPath, isRawAsset);
List<string> assetTags = GetAssetTags(grouper);
var collectAssetInfo = new CollectAssetInfo(bundleName, assetPath, assetTags, isRawAsset, NotWriteToAssetList);
collectAssetInfo.DependAssets = GetAllDependencies(assetPath);
@@ -91,9 +91,10 @@ namespace YooAsset.Editor
if (isRawAsset && NotWriteToAssetList)
UnityEngine.Debug.LogWarning($"Are you sure raw file are not write to asset list : {assetPath}");
string bundleName = GetBundleName(grouper, assetPath);
string bundleName = GetBundleName(grouper, assetPath, isRawAsset);
List<string> assetTags = GetAssetTags(grouper);
var collectAssetInfo = new CollectAssetInfo(bundleName, assetPath, assetTags, isRawAsset, NotWriteToAssetList);
collectAssetInfo.DependAssets = GetAllDependencies(assetPath);
result.Add(assetPath, collectAssetInfo);
}
else
@@ -120,7 +121,7 @@ namespace YooAsset.Editor
return false;
string ext = System.IO.Path.GetExtension(assetPath);
if (ext == "" || ext == ".dll" || ext == ".cs" || ext == ".js" || ext == ".boo" || ext == ".meta")
if (ext == "" || ext == ".dll" || ext == ".cs" || ext == ".js" || ext == ".boo" || ext == ".meta" || ext == ".cginc")
return false;
return true;
@@ -139,22 +140,18 @@ namespace YooAsset.Editor
IFilterRule filterRuleInstance = AssetBundleGrouperSettingData.GetFilterRuleInstance(FilterRuleName);
return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath));
}
private string GetBundleName(AssetBundleGrouper grouper, string assetPath)
private string GetBundleName(AssetBundleGrouper grouper, string assetPath, bool isRawAsset)
{
// 如果收集全路径着色器
if (AssetBundleGrouperSettingData.Setting.AutoCollectShaders)
{
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
{
return RevisedBundleName(AssetBundleGrouperSettingData.Setting.ShadersBundleName);
}
}
string shaderBundleName = CollectShaderBundleName(assetPath);
if (string.IsNullOrEmpty(shaderBundleName) == false)
return shaderBundleName;
// 根据规则设置获取资源包名称
IPackRule packRuleInstance = AssetBundleGrouperSettingData.GetPackRuleInstance(PackRuleName);
string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, grouper.GrouperName));
return RevisedBundleName(bundleName);
{
IPackRule packRuleInstance = AssetBundleGrouperSettingData.GetPackRuleInstance(PackRuleName);
string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, grouper.GrouperName));
return CorrectBundleName(bundleName, isRawAsset);
}
}
private List<string> GetAssetTags(AssetBundleGrouper grouper)
{
@@ -179,13 +176,39 @@ namespace YooAsset.Editor
return result;
}
/// <summary>
/// 收集着色器的资源包名称
/// </summary>
public static string CollectShaderBundleName(string assetPath)
{
// 如果自动收集所有的着色器
if (AssetBundleGrouperSettingData.Setting.AutoCollectShaders)
{
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
{
string bundleName = AssetBundleGrouperSettingData.Setting.ShadersBundleName;
return CorrectBundleName(bundleName, false);
}
}
return null;
}
/// <summary>
/// 修正资源包名
/// 修正资源包名
/// </summary>
public static string RevisedBundleName(string bundleName)
public static string CorrectBundleName(string bundleName, bool isRawBundle)
{
return EditorTools.GetRegularPath(bundleName).ToLower();
if (isRawBundle)
{
string fullName = $"{bundleName}.{YooAssetSettingsData.Setting.RawFileVariant}";
return EditorTools.GetRegularPath(fullName).ToLower();
}
else
{
string fullName = $"{bundleName}.{YooAssetSettingsData.Setting.AssetBundleFileVariant}";
return EditorTools.GetRegularPath(fullName).ToLower(); ;
}
}
}
}

View File

@@ -14,6 +14,11 @@ 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>();
/// <summary>
/// 配置数据是否被修改
/// </summary>
public static bool IsDirty { private set; get; } = false;
private static AssetBundleGrouperSetting _setting = null;
public static AssetBundleGrouperSetting Setting
@@ -147,8 +152,10 @@ namespace YooAsset.Editor
{
if (Setting != null)
{
IsDirty = false;
EditorUtility.SetDirty(Setting);
AssetDatabase.SaveAssets();
Debug.Log($"{nameof(AssetBundleGrouperSetting)}.asset is saved!");
}
}
@@ -202,42 +209,42 @@ namespace YooAsset.Editor
// 着色器编辑相关
public static void ModifyShader(bool isCollectAllShaders, string shadersBundleName)
{
if (string.IsNullOrEmpty(shadersBundleName))
return;
Setting.AutoCollectShaders = isCollectAllShaders;
Setting.ShadersBundleName = shadersBundleName;
SaveFile();
IsDirty = true;
}
// 资源分组编辑相关
public static void CreateGrouper(string grouperName, string grouperDesc, string assetTags, bool saveFile = true)
public static void CreateGrouper(string grouperName, string grouperDesc, string assetTags)
{
AssetBundleGrouper grouper = new AssetBundleGrouper();
grouper.GrouperName = grouperName;
grouper.GrouperDesc = grouperDesc;
grouper.AssetTags = assetTags;
Setting.Groupers.Add(grouper);
if (saveFile)
SaveFile();
IsDirty = true;
}
public static void RemoveGrouper(AssetBundleGrouper grouper)
{
if (Setting.Groupers.Remove(grouper))
{
SaveFile();
IsDirty = true;
}
else
{
Debug.LogWarning($"Failed remove grouper : {grouper.GrouperName}");
}
}
public static void ModifyGrouper(AssetBundleGrouper grouper)
{
if (grouper != null)
{
SaveFile();
IsDirty = true;
}
}
// 资源收集器编辑相关
public static void CreateCollector(AssetBundleGrouper grouper, string collectPath, string packRuleName, string filterRuleName, bool notWriteToAssetList, bool saveFile = true)
public static void CreateCollector(AssetBundleGrouper grouper, string collectPath, string packRuleName, string filterRuleName, bool notWriteToAssetList)
{
AssetBundleCollector collector = new AssetBundleCollector();
collector.CollectPath = collectPath;
@@ -245,22 +252,24 @@ namespace YooAsset.Editor
collector.FilterRuleName = filterRuleName;
collector.NotWriteToAssetList = notWriteToAssetList;
grouper.Collectors.Add(collector);
if (saveFile)
SaveFile();
IsDirty = true;
}
public static void RemoveCollector(AssetBundleGrouper grouper, AssetBundleCollector collector)
{
if (grouper.Collectors.Remove(collector))
{
SaveFile();
IsDirty = true;
}
else
{
Debug.LogWarning($"Failed remove collector : {collector.CollectPath}");
}
}
public static void ModifyCollector(AssetBundleGrouper grouper, AssetBundleCollector collector)
{
if (grouper != null && collector != null)
{
SaveFile();
IsDirty = true;
}
}
}

View File

@@ -152,7 +152,12 @@ namespace YooAsset.Editor
Debug.LogError(e.ToString());
}
}
public void OnDestroy()
{
if (AssetBundleGrouperSettingData.IsDirty)
AssetBundleGrouperSettingData.SaveFile();
}
// 刷新窗体
private void RefreshWindow()
{
@@ -222,7 +227,7 @@ namespace YooAsset.Editor
}
private void AddGrouperBtn_clicked()
{
AssetBundleGrouperSettingData.CreateGrouper("Default Grouper", string.Empty, string.Empty, true);
AssetBundleGrouperSettingData.CreateGrouper("Default Grouper", string.Empty, string.Empty);
FillGrouperViewData();
}
private void RemoveGrouperBtn_clicked()

View File

@@ -234,7 +234,7 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 250;
label.style.width = 280;
element.Add(label);
}

View File

@@ -11,7 +11,7 @@
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Depend Bundles" display-tooltip-when-elided="true" name="BottomBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Size" display-tooltip-when-elided="true" name="BottomBar2" style="width: 100px; -unity-text-align: middle-left; flex-grow: 0;" />
<uie:ToolbarButton text="Hash" display-tooltip-when-elided="true" name="BottomBar3" style="width: 250px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Hash" display-tooltip-when-elided="true" name="BottomBar3" style="width: 280px; -unity-text-align: middle-left;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="BottomListView" item-height="18" style="flex-grow: 1;" />
</ui:VisualElement>

View File

@@ -145,17 +145,7 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 250;
element.Add(label);
}
{
var label = new Label();
label.name = "Label4";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 60;
label.style.width = 280;
element.Add(label);
}
@@ -188,10 +178,6 @@ namespace YooAsset.Editor
var label3 = element.Q<Label>("Label3");
label3.text = bundleInfo.Hash;
// Version
var label4 = element.Q<Label>("Label4");
label4.text = bundleInfo.Version.ToString();
// Tags
var label5 = element.Q<Label>("Label5");
label5.text = GetTagsString(bundleInfo.Tags);
@@ -251,7 +237,7 @@ namespace YooAsset.Editor
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 250;
label.style.width = 280;
element.Add(label);
}

View File

@@ -4,8 +4,7 @@
<uie:Toolbar name="TopBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Bundle Name" display-tooltip-when-elided="true" name="TopBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Size" display-tooltip-when-elided="true" name="TopBar2" style="width: 100px; -unity-text-align: middle-left; flex-grow: 0;" />
<uie:ToolbarButton text="Hash" display-tooltip-when-elided="true" name="TopBar3" style="width: 250px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Version" display-tooltip-when-elided="true" name="TopBar4" style="width: 60px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Hash" display-tooltip-when-elided="true" name="TopBar3" style="width: 280px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="Tags" display-tooltip-when-elided="true" name="TopBar5" style="width: 80px; -unity-text-align: middle-left; flex-grow: 1;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="TopListView" item-height="18" style="flex-grow: 1;" />
@@ -14,7 +13,7 @@
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Include Assets" display-tooltip-when-elided="true" name="BottomBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Size" display-tooltip-when-elided="true" name="BottomBar2" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="GUID" display-tooltip-when-elided="true" name="BottomBar3" style="width: 250px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="GUID" display-tooltip-when-elided="true" name="BottomBar3" style="width: 280px; -unity-text-align: middle-left;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="BottomListView" item-height="18" style="flex-grow: 1;" />
</ui:VisualElement>

View File

@@ -76,6 +76,7 @@ namespace YooAsset.Editor
_items.Add(new ItemWrapper(string.Empty, string.Empty));
_items.Add(new ItemWrapper("构建参数", string.Empty));
_items.Add(new ItemWrapper("DryRunBuild", $"{buildReport.Summary.DryRunBuild}"));
_items.Add(new ItemWrapper("ForceRebuild", $"{buildReport.Summary.ForceRebuild}"));
_items.Add(new ItemWrapper("BuildinTags", $"{buildReport.Summary.BuildinTags}"));
_items.Add(new ItemWrapper("CompressOption", $"{buildReport.Summary.CompressOption}"));

View File

@@ -4,9 +4,9 @@ namespace YooAsset.Editor
public class EditorDefine
{
/// <summary>
/// 资源包收集工具的配置文件存储路径
/// 资源包构建工具的配置文件存储路径
/// </summary>
public const string AssetBundleCollectorSettingFilePath = "Assets/YooAssetSetting/AssetBundleCollectorSetting.asset";
public const string AssetBundleBuilderSettingFilePath = "Assets/YooAssetSetting/AssetBundleBuilderSetting.asset";
/// <summary>
/// 资源包分组工具的配置文件存储路径

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -8,9 +9,10 @@ namespace YooAsset
{
internal static class AssetSystem
{
private static readonly List<AssetBundleLoader> _loaders = new List<AssetBundleLoader>(1000);
private static readonly List<AssetBundleLoaderBase> _loaders = new List<AssetBundleLoaderBase>(1000);
private static readonly List<ProviderBase> _providers = new List<ProviderBase>(1000);
private static readonly Dictionary<string, SceneOperationHandle> _sceneHandles = new Dictionary<string, SceneOperationHandle>(100);
/// <summary>
/// 在编辑器下模拟运行
/// </summary>
@@ -90,12 +92,12 @@ namespace YooAsset
{
for (int i = _loaders.Count - 1; i >= 0; i--)
{
AssetBundleLoader loader = _loaders[i];
AssetBundleLoaderBase loader = _loaders[i];
loader.TryDestroyAllProviders();
}
for (int i = _loaders.Count - 1; i >= 0; i--)
{
AssetBundleLoader loader = _loaders[i];
AssetBundleLoaderBase loader = _loaders[i];
if (loader.CanDestroy())
{
loader.Destroy(false);
@@ -127,23 +129,21 @@ namespace YooAsset
}
/// <summary>
/// 异步加载原生文件
/// </summary>
public static RawFileOperation LoadRawFileAsync(string assetPath, string savePath)
{
string bundleName = BundleServices.GetBundleName(assetPath);
BundleInfo bundleInfo = BundleServices.GetBundleInfo(bundleName);
RawFileOperation operation = new RawFileOperation(bundleInfo, savePath);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
/// <summary>
/// 异步加载场景
/// </summary>
public static SceneOperationHandle LoadSceneAsync(string scenePath, LoadSceneMode sceneMode, bool activateOnLoad, int priority)
{
// 注意:场景句柄永远保持唯一
if (_sceneHandles.ContainsKey(scenePath))
return _sceneHandles[scenePath];
// 如果加载的是主场景,则卸载所有缓存的场景
if (sceneMode == LoadSceneMode.Single)
{
UnloadAllScene();
}
ProviderBase provider = TryGetProvider(scenePath);
if (provider == null)
{
@@ -151,9 +151,13 @@ namespace YooAsset
provider = new DatabaseSceneProvider(scenePath, sceneMode, activateOnLoad, priority);
else
provider = new BundledSceneProvider(scenePath, sceneMode, activateOnLoad, priority);
provider.InitSpawnDebugInfo();
_providers.Add(provider);
}
return provider.CreateHandle() as SceneOperationHandle;
var handle = provider.CreateHandle() as SceneOperationHandle;
_sceneHandles.Add(scenePath, handle);
return handle;
}
/// <summary>
@@ -168,6 +172,7 @@ namespace YooAsset
provider = new DatabaseAssetProvider(assetPath, assetType);
else
provider = new BundledAssetProvider(assetPath, assetType);
provider.InitSpawnDebugInfo();
_providers.Add(provider);
}
return provider.CreateHandle() as AssetOperationHandle;
@@ -185,28 +190,71 @@ namespace YooAsset
provider = new DatabaseSubAssetsProvider(assetPath, assetType);
else
provider = new BundledSubAssetsProvider(assetPath, assetType);
provider.InitSpawnDebugInfo();
_providers.Add(provider);
}
return provider.CreateHandle() as SubAssetsOperationHandle;
}
internal static AssetBundleLoader CreateOwnerAssetBundleLoader(string assetPath)
internal static void UnloadSubScene(ProviderBase provider)
{
string scenePath = provider.AssetPath;
if (_sceneHandles.ContainsKey(scenePath) == false)
throw new Exception("Should never get here !");
// 释放子场景句柄
_sceneHandles[scenePath].ReleaseInternal();
_sceneHandles.Remove(scenePath);
// 卸载未被使用的资源(包括场景)
AssetSystem.UnloadUnusedAssets();
// 检验子场景是否销毁
if (provider.IsDestroyed == false)
{
throw new Exception("Should never get here !");
}
}
internal static void UnloadAllScene()
{
// 释放所有场景句柄
foreach (var valuePair in _sceneHandles)
{
valuePair.Value.ReleaseInternal();
}
_sceneHandles.Clear();
// 卸载未被使用的资源(包括场景)
AssetSystem.UnloadUnusedAssets();
// 检验所有场景是否销毁
foreach (var provider in _providers)
{
if (provider.IsSceneProvider())
{
if (provider.IsDestroyed == false)
throw new Exception("Should never get here !");
}
}
}
internal static AssetBundleLoaderBase CreateOwnerAssetBundleLoader(string assetPath)
{
string bundleName = BundleServices.GetBundleName(assetPath);
BundleInfo bundleInfo = BundleServices.GetBundleInfo(bundleName);
return CreateAssetBundleLoaderInternal(bundleInfo);
}
internal static List<AssetBundleLoader> CreateDependAssetBundleLoaders(string assetPath)
internal static List<AssetBundleLoaderBase> CreateDependAssetBundleLoaders(string assetPath)
{
List<AssetBundleLoader> result = new List<AssetBundleLoader>();
List<AssetBundleLoaderBase> result = new List<AssetBundleLoaderBase>();
string[] depends = BundleServices.GetAllDependencies(assetPath);
if (depends != null)
{
foreach (var dependBundleName in depends)
{
BundleInfo dependBundleInfo = BundleServices.GetBundleInfo(dependBundleName);
AssetBundleLoader dependLoader = CreateAssetBundleLoaderInternal(dependBundleInfo);
AssetBundleLoaderBase dependLoader = CreateAssetBundleLoaderInternal(dependBundleInfo);
result.Add(dependLoader);
}
}
@@ -220,24 +268,29 @@ namespace YooAsset
}
}
private static AssetBundleLoader CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
private static AssetBundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
{
// 如果加载器已经存在
AssetBundleLoader loader = TryGetAssetBundleLoader(bundleInfo.BundleName);
AssetBundleLoaderBase loader = TryGetAssetBundleLoader(bundleInfo.BundleName);
if (loader != null)
return loader;
// 新增下载需求
loader = new AssetBundleLoader(bundleInfo);
#if UNITY_WEBGL
loader = new AssetBundleWebLoader(bundleInfo);
#else
loader = new AssetBundleFileLoader(bundleInfo);
#endif
_loaders.Add(loader);
return loader;
}
private static AssetBundleLoader TryGetAssetBundleLoader(string bundleName)
private static AssetBundleLoaderBase TryGetAssetBundleLoader(string bundleName)
{
AssetBundleLoader loader = null;
AssetBundleLoaderBase loader = null;
for (int i = 0; i < _loaders.Count; i++)
{
AssetBundleLoader temp = _loaders[i];
AssetBundleLoaderBase temp = _loaders[i];
if (temp.BundleFileInfo.BundleName.Equals(bundleName))
{
loader = temp;
@@ -261,6 +314,7 @@ namespace YooAsset
return provider;
}
#region
internal static void GetDebugReport(DebugReport report)
{
@@ -272,6 +326,8 @@ namespace YooAsset
{
DebugProviderInfo providerInfo = new DebugProviderInfo();
providerInfo.AssetPath = provider.AssetPath;
providerInfo.SpawnScene = provider.SpawnScene;
providerInfo.SpawnTime = provider.SpawnTime;
providerInfo.RefCount = provider.RefCount;
providerInfo.Status = provider.Status;
providerInfo.BundleInfos.Clear();

View File

@@ -2,7 +2,7 @@
namespace YooAsset
{
public class AssetOperationHandle : OperationHandleBase
public sealed class AssetOperationHandle : OperationHandleBase
{
private System.Action<AssetOperationHandle> _callback;
@@ -11,10 +11,7 @@ namespace YooAsset
}
internal override void InvokeCallback()
{
if (IsValid)
{
_callback?.Invoke(this);
}
_callback?.Invoke(this);
}
/// <summary>
@@ -78,7 +75,7 @@ namespace YooAsset
/// <returns></returns>
public GameObject InstantiateSync(Transform parent = null)
{
return InstantiateSync(Vector3.zero, Quaternion.identity, parent);
return InstantiateSyncInternal(Vector3.zero, Quaternion.identity, parent, false);
}
/// <summary>
@@ -89,15 +86,7 @@ namespace YooAsset
/// <param name="parent">父类对象</param>
public GameObject InstantiateSync(Vector3 position, Quaternion rotation, Transform parent = null)
{
if (IsValid == false)
return null;
if (_provider.AssetObject == null)
return null;
if (parent == null)
return UnityEngine.Object.Instantiate(_provider.AssetObject as GameObject, position, rotation);
else
return UnityEngine.Object.Instantiate(_provider.AssetObject as GameObject, position, rotation, parent);
return InstantiateSyncInternal(position, rotation, parent, true);
}
/// <summary>
@@ -106,7 +95,7 @@ namespace YooAsset
/// <param name="parent">父类对象</param>
public InstantiateOperation InstantiateAsync(Transform parent = null)
{
return InstantiateAsync(Vector3.zero, Quaternion.identity, parent);
return InstantiateAsyncInternal(Vector3.zero, Quaternion.identity, parent, false);
}
/// <summary>
@@ -117,7 +106,35 @@ namespace YooAsset
/// <param name="parent">父类对象</param>
public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation, Transform parent = null)
{
InstantiateOperation operation = new InstantiateOperation(this, position, rotation, parent);
return InstantiateAsyncInternal(position, rotation, parent, true);
}
private GameObject InstantiateSyncInternal(Vector3 position, Quaternion rotation, Transform parent, bool setPositionRotation)
{
if (IsValid == false)
return null;
if (_provider.AssetObject == null)
return null;
if (setPositionRotation)
{
if (parent == null)
return UnityEngine.Object.Instantiate(_provider.AssetObject as GameObject, position, rotation);
else
return UnityEngine.Object.Instantiate(_provider.AssetObject as GameObject, position, rotation, parent);
}
else
{
if (parent == null)
return UnityEngine.Object.Instantiate(_provider.AssetObject as GameObject);
else
return UnityEngine.Object.Instantiate(_provider.AssetObject as GameObject, parent);
}
}
private InstantiateOperation InstantiateAsyncInternal(Vector3 position, Quaternion rotation, Transform parent, bool setPositionRotation)
{
InstantiateOperation operation = new InstantiateOperation(this, position, rotation, parent, setPositionRotation);
OperationSystem.ProcessOperaiton(operation);
return operation;
}

View File

@@ -4,11 +4,13 @@ namespace YooAsset
{
public abstract class OperationHandleBase : IEnumerator
{
private readonly string _cachedAssetPath;
internal ProviderBase _provider { private set; get; }
internal OperationHandleBase(ProviderBase provider)
{
_provider = provider;
_cachedAssetPath = provider.AssetPath;
}
internal abstract void InvokeCallback();
@@ -63,7 +65,18 @@ namespace YooAsset
{
get
{
return _provider != null && _provider.IsDestroyed == false;
if (_provider != null && _provider.IsDestroyed == false)
{
return true;
}
else
{
if (_provider == null)
YooLogger.Warning($"Operation handle is released : {_cachedAssetPath}");
else if (_provider.IsDestroyed)
YooLogger.Warning($"Provider is destroyed : {_cachedAssetPath}");
return false;
}
}
}
@@ -82,7 +95,7 @@ namespace YooAsset
/// <summary>
/// 异步操作任务
/// </summary>
public System.Threading.Tasks.Task<object> Task
public System.Threading.Tasks.Task Task
{
get { return _provider.Task; }
}

View File

@@ -11,10 +11,7 @@ namespace YooAsset
}
internal override void InvokeCallback()
{
if (IsValid)
{
_callback?.Invoke(this);
}
_callback?.Invoke(this);
}
/// <summary>
@@ -72,10 +69,35 @@ namespace YooAsset
}
/// <summary>
/// 异步卸载场景
/// 是否为主场景
/// </summary>
public bool IsMainScene()
{
if (IsValid == false)
return false;
if (_provider is DatabaseSceneProvider)
{
var temp = _provider as DatabaseSceneProvider;
return temp.SceneMode == LoadSceneMode.Single;
}
else if (_provider is BundledSceneProvider)
{
var temp = _provider as BundledSceneProvider;
return temp.SceneMode == LoadSceneMode.Single;
}
else
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 异步卸载子场景
/// </summary>
public UnloadSceneOperation UnloadAsync()
{
// 如果句柄无效
if (IsValid == false)
{
string error = $"{nameof(SceneOperationHandle)} is invalid.";
@@ -84,54 +106,23 @@ namespace YooAsset
return operation;
}
ProviderBase provider = _provider;
// 释放场景句柄
ReleaseInternal();
// 卸载未被使用的资源(包括场景)
AssetSystem.UnloadUnusedAssets();
// 返回场景卸载异步操作类
if (provider.IsDestroyed == false)
// 如果是主场景
if (IsMainScene())
{
YooLogger.Warning($"Scene can not unload. The provider not destroyed : {provider.AssetPath}");
var operation = new UnloadSceneOperation();
string error = $"Cannot unload main scene. Use {nameof(YooAssets.LoadSceneAsync)} method to change the main scene !";
YooLogger.Error(error);
var operation = new UnloadSceneOperation(error);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else
{
if (IsAdditiveScene(provider))
{
var operation = new UnloadSceneOperation(provider.SceneObject);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else
{
var operation = new UnloadSceneOperation();
OperationSystem.ProcessOperaiton(operation);
return operation;
}
}
}
private bool IsAdditiveScene(ProviderBase provider)
{
if (provider is DatabaseSceneProvider)
// 卸载子场景
Scene sceneObject = SceneObject;
AssetSystem.UnloadSubScene(_provider);
{
var temp = provider as DatabaseSceneProvider;
return temp.SceneMode == LoadSceneMode.Additive;
}
else if (provider is BundledSceneProvider)
{
var temp = provider as BundledSceneProvider;
return temp.SceneMode == LoadSceneMode.Additive;
}
else
{
throw new System.NotImplementedException();
var operation = new UnloadSceneOperation(sceneObject);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
}
}

View File

@@ -1,7 +1,7 @@

namespace YooAsset
{
public class SubAssetsOperationHandle : OperationHandleBase
public sealed class SubAssetsOperationHandle : OperationHandleBase
{
private System.Action<SubAssetsOperationHandle> _callback;
@@ -10,10 +10,7 @@ namespace YooAsset
}
internal override void InvokeCallback()
{
if (IsValid)
{
_callback?.Invoke(this);
}
_callback?.Invoke(this);
}
/// <summary>

View File

@@ -0,0 +1,198 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class AssetBundleFileLoader : AssetBundleLoaderBase
{
private enum ESteps
{
None = 0,
Download,
CheckDownload,
LoadFile,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
private string _fileLoadPath;
private bool _isWaitForAsyncComplete = false;
private bool _isShowWaitForAsyncError = false;
private DownloaderBase _downloader;
private AssetBundleCreateRequest _cacheRequest;
public AssetBundleFileLoader(BundleInfo bundleInfo) : base(bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (BundleFileInfo.LoadMode == BundleInfo.ELoadMode.None)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
return;
}
if (BundleFileInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
_fileLoadPath = BundleFileInfo.GetCacheLoadPath();
}
else if (BundleFileInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadFile;
_fileLoadPath = BundleFileInfo.GetStreamingLoadPath();
}
else if (BundleFileInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadFile;
_fileLoadPath = BundleFileInfo.GetCacheLoadPath();
}
else
{
throw new System.NotImplementedException(BundleFileInfo.LoadMode.ToString());
}
}
// 1. 从服务器下载
if (_steps == ESteps.Download)
{
int failedTryAgain = int.MaxValue;
_downloader = DownloadSystem.BeginDownload(BundleFileInfo, failedTryAgain);
_steps = ESteps.CheckDownload;
}
// 2. 检测服务器下载结果
if (_steps == ESteps.CheckDownload)
{
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_downloader.ReportError();
_steps = ESteps.Done;
Status = EStatus.Failed;
}
else
{
_steps = ESteps.LoadFile;
}
}
// 3. 加载AssetBundle
if (_steps == ESteps.LoadFile)
{
#if UNITY_EDITOR
// 注意Unity2017.4编辑器模式下如果AssetBundle文件不存在会导致编辑器崩溃这里做了预判。
if (System.IO.File.Exists(_fileLoadPath) == false)
{
YooLogger.Warning($"Not found assetBundle file : {_fileLoadPath}");
_steps = ESteps.Done;
Status = EStatus.Failed;
return;
}
#endif
// Load assetBundle file
if (BundleFileInfo.IsEncrypted)
{
if (AssetSystem.DecryptionServices == null)
throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {BundleFileInfo.BundleName}");
ulong offset = AssetSystem.DecryptionServices.GetFileOffset(BundleFileInfo);
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath, 0, offset);
else
_cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset);
}
else
{
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath);
else
_cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath);
}
_steps = ESteps.CheckFile;
}
// 4. 检测AssetBundle加载结果
if (_steps == ESteps.CheckFile)
{
if (_cacheRequest != null)
{
if (_isWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
CacheBundle = _cacheRequest.assetBundle;
}
else
{
if (_cacheRequest.isDone == false)
return;
CacheBundle = _cacheRequest.assetBundle;
}
}
// Check error
if (CacheBundle == null)
{
YooLogger.Error($"Failed to load assetBundle file : {BundleFileInfo.BundleName}");
_steps = ESteps.Done;
Status = EStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
_isWaitForAsyncComplete = true;
int frame = 1000;
while (true)
{
// 保险机制
// 注意如果需要从WEB端下载资源可能会触发保险机制
frame--;
if (frame == 0)
{
if (_isShowWaitForAsyncError == false)
{
_isShowWaitForAsyncError = true;
YooLogger.Error($"WaitForAsyncComplete failed ! BundleName : {BundleFileInfo.BundleName} States : {Status}");
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}

View File

@@ -1,301 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal class AssetBundleLoader
{
public enum EStatus
{
None = 0,
Download,
CheckDownload,
LoadFile,
CheckFile,
Success,
Fail,
}
/// <summary>
/// 资源包文件信息
/// </summary>
public BundleInfo BundleFileInfo { private set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
/// <summary>
/// 加载状态
/// </summary>
public EStatus Status { private set; get; }
/// <summary>
/// 是否已经销毁
/// </summary>
public bool IsDestroyed { private set; get; } = false;
private readonly List<ProviderBase> _providers = new List<ProviderBase>(100);
private bool _isWaitForAsyncComplete = false;
private bool _isShowWaitForAsyncError = false;
private DownloaderBase _downloader;
private AssetBundleCreateRequest _cacheRequest;
internal AssetBundle CacheBundle { private set; get; }
public AssetBundleLoader(BundleInfo bundleInfo)
{
BundleFileInfo = bundleInfo;
RefCount = 0;
Status = EStatus.None;
}
/// <summary>
/// 添加附属的资源提供者
/// </summary>
public void AddProvider(ProviderBase provider)
{
if (_providers.Contains(provider) == false)
_providers.Add(provider);
}
/// <summary>
/// 引用(引用计数递加)
/// </summary>
public void Reference()
{
RefCount++;
}
/// <summary>
/// 释放(引用计数递减)
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 轮询更新
/// </summary>
public void Update()
{
// 如果资源文件加载完毕
if (IsDone())
return;
if (Status == EStatus.None)
{
// 检测加载地址是否为空
if (string.IsNullOrEmpty(BundleFileInfo.LocalPath))
{
Status = EStatus.Fail;
return;
}
if (string.IsNullOrEmpty(BundleFileInfo.RemoteMainURL))
Status = EStatus.LoadFile;
else
Status = EStatus.Download;
}
// 1. 从服务器下载
if (Status == EStatus.Download)
{
int failedTryAgain = int.MaxValue;
_downloader = DownloadSystem.BeginDownload(BundleFileInfo, failedTryAgain);
Status = EStatus.CheckDownload;
}
// 2. 检测服务器下载结果
if (Status == EStatus.CheckDownload)
{
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_downloader.ReportError();
Status = EStatus.Fail;
}
else
{
Status = EStatus.LoadFile;
}
}
// 3. 加载AssetBundle
if (Status == EStatus.LoadFile)
{
#if UNITY_EDITOR
// 注意Unity2017.4编辑器模式下如果AssetBundle文件不存在会导致编辑器崩溃这里做了预判。
if (System.IO.File.Exists(BundleFileInfo.LocalPath) == false)
{
YooLogger.Warning($"Not found assetBundle file : {BundleFileInfo.LocalPath}");
Status = EStatus.Fail;
return;
}
#endif
// Load assetBundle file
if (BundleFileInfo.IsEncrypted)
{
if (AssetSystem.DecryptionServices == null)
throw new Exception($"{nameof(AssetBundleLoader)} need IDecryptServices : {BundleFileInfo.BundleName}");
ulong offset = AssetSystem.DecryptionServices.GetFileOffset(BundleFileInfo);
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(BundleFileInfo.LocalPath, 0, offset);
else
_cacheRequest = AssetBundle.LoadFromFileAsync(BundleFileInfo.LocalPath, 0, offset);
}
else
{
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(BundleFileInfo.LocalPath);
else
_cacheRequest = AssetBundle.LoadFromFileAsync(BundleFileInfo.LocalPath);
}
Status = EStatus.CheckFile;
}
// 4. 检测AssetBundle加载结果
if (Status == EStatus.CheckFile)
{
if (_cacheRequest != null)
{
if (_isWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
CacheBundle = _cacheRequest.assetBundle;
}
else
{
if (_cacheRequest.isDone == false)
return;
CacheBundle = _cacheRequest.assetBundle;
}
}
// Check error
if (CacheBundle == null)
{
YooLogger.Error($"Failed to load assetBundle file : {BundleFileInfo.BundleName}");
Status = EStatus.Fail;
}
else
{
Status = EStatus.Success;
}
}
}
/// <summary>
/// 销毁
/// </summary>
public void Destroy(bool forceDestroy)
{
IsDestroyed = true;
// Check fatal
if (forceDestroy == false)
{
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {BundleFileInfo.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {BundleFileInfo.BundleName}");
}
if (CacheBundle != null)
{
CacheBundle.Unload(true);
CacheBundle = null;
}
}
/// <summary>
/// 是否完毕(无论成功或失败)
/// </summary>
public bool IsDone()
{
return Status == EStatus.Success || Status == EStatus.Fail;
}
/// <summary>
/// 是否可以销毁
/// </summary>
public bool CanDestroy()
{
if (IsDone() == false)
return false;
return RefCount <= 0;
}
/// <summary>
/// 在满足条件的前提下,销毁所有资源提供者
/// </summary>
public void TryDestroyAllProviders()
{
if (IsDone() == false)
return;
// 注意必须等待所有Provider可以销毁的时候才可以释放Bundle文件。
foreach (var provider in _providers)
{
if (provider.CanDestroy() == false)
return;
}
// 除了自己没有其它引用
if (RefCount > _providers.Count)
return;
// 销毁所有Providers
foreach (var provider in _providers)
{
provider.Destory();
}
// 从列表里移除Providers
AssetSystem.RemoveBundleProviders(_providers);
_providers.Clear();
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public void WaitForAsyncComplete()
{
_isWaitForAsyncComplete = true;
int frame = 1000;
while (true)
{
// 保险机制
// 注意如果需要从WEB端下载资源可能会触发保险机制
frame--;
if (frame == 0)
{
if (_isShowWaitForAsyncError == false)
{
_isShowWaitForAsyncError = true;
YooLogger.Error($"WaitForAsyncComplete failed ! BundleName : {BundleFileInfo.BundleName} States : {Status}");
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}

View File

@@ -0,0 +1,155 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal abstract class AssetBundleLoaderBase
{
public enum EStatus
{
None = 0,
Succeed,
Failed
}
/// <summary>
/// 资源包文件信息
/// </summary>
public BundleInfo BundleFileInfo { private set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
/// <summary>
/// 加载状态
/// </summary>
public EStatus Status { protected set; get; }
/// <summary>
/// 是否已经销毁
/// </summary>
public bool IsDestroyed { private set; get; } = false;
private readonly List<ProviderBase> _providers = new List<ProviderBase>(100);
internal AssetBundle CacheBundle { set; get; }
public AssetBundleLoaderBase(BundleInfo bundleInfo)
{
BundleFileInfo = bundleInfo;
RefCount = 0;
Status = EStatus.None;
}
/// <summary>
/// 添加附属的资源提供者
/// </summary>
public void AddProvider(ProviderBase provider)
{
if (_providers.Contains(provider) == false)
_providers.Add(provider);
}
/// <summary>
/// 引用(引用计数递加)
/// </summary>
public void Reference()
{
RefCount++;
}
/// <summary>
/// 释放(引用计数递减)
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 轮询更新
/// </summary>
public abstract void Update();
/// <summary>
/// 销毁
/// </summary>
public void Destroy(bool forceDestroy)
{
IsDestroyed = true;
// Check fatal
if (forceDestroy == false)
{
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {BundleFileInfo.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {BundleFileInfo.BundleName}");
}
if (CacheBundle != null)
{
CacheBundle.Unload(true);
CacheBundle = null;
}
}
/// <summary>
/// 是否完毕(无论成功或失败)
/// </summary>
public bool IsDone()
{
return Status == EStatus.Succeed || Status == EStatus.Failed;
}
/// <summary>
/// 是否可以销毁
/// </summary>
public bool CanDestroy()
{
if (IsDone() == false)
return false;
return RefCount <= 0;
}
/// <summary>
/// 在满足条件的前提下,销毁所有资源提供者
/// </summary>
public void TryDestroyAllProviders()
{
if (IsDone() == false)
return;
// 注意必须等待所有Provider可以销毁的时候才可以释放Bundle文件。
foreach (var provider in _providers)
{
if (provider.CanDestroy() == false)
return;
}
// 除了自己没有其它引用
if (RefCount > _providers.Count)
return;
// 销毁所有Providers
foreach (var provider in _providers)
{
provider.Destory();
}
// 从列表里移除Providers
AssetSystem.RemoveBundleProviders(_providers);
_providers.Clear();
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public abstract void WaitForAsyncComplete();
}
}

View File

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

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal sealed class AssetBundleWebLoader : AssetBundleLoaderBase
{
private enum ESteps
{
None = 0,
LoadFile,
CheckFile,
TryLoad,
Done,
}
private ESteps _steps = ESteps.None;
private float _tryTimer = 0;
private string _webURL;
private UnityWebRequest _webRequest;
public AssetBundleWebLoader(BundleInfo bundleInfo) : base(bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (BundleFileInfo.LoadMode == BundleInfo.ELoadMode.None)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
return;
}
if (BundleFileInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadFile;
_webURL = BundleFileInfo.GetStreamingLoadPath();
}
else
{
throw new System.NotImplementedException(BundleFileInfo.LoadMode.ToString());
}
}
// 1. 从服务器或缓存中获取AssetBundle文件
if (_steps == ESteps.LoadFile)
{
string hash = StringUtility.RemoveExtension(BundleFileInfo.Hash);
_webRequest = UnityWebRequestAssetBundle.GetAssetBundle(_webURL, Hash128.Parse(hash));
_webRequest.SendWebRequest();
_steps = ESteps.CheckFile;
}
// 2. 检测获取的AssetBundle文件
if (_steps == ESteps.CheckFile)
{
if (_webRequest.isDone == false)
return;
#if UNITY_2020_1_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
#endif
{
Debug.LogWarning($"Failed to get asset bundle form web : {_webURL} Error : {_webRequest.error}");
_steps = ESteps.TryLoad;
_tryTimer = 0;
}
else
{
CacheBundle = DownloadHandlerAssetBundle.GetContent(_webRequest);
if (CacheBundle == null)
{
Debug.LogError($"Get asset bundle error : {_webRequest.error}");
_steps = ESteps.Done;
Status = EStatus.Failed;
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
// 3. 如果获取失败,重新尝试
if (_steps == ESteps.TryLoad)
{
_tryTimer += Time.unscaledDeltaTime;
if (_tryTimer > 1f)
{
_webRequest.Dispose();
_webRequest = null;
_steps = ESteps.LoadFile;
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
throw new System.NotImplementedException($"WebGL platform not support {nameof(WaitForAsyncComplete)}");
}
}
}

View File

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

View File

@@ -9,7 +9,7 @@ namespace YooAsset
/// <summary>
/// 依赖的资源包加载器列表
/// </summary>
private readonly List<AssetBundleLoader> _dependBundles;
private readonly List<AssetBundleLoaderBase> _dependBundles;
public DependAssetBundleGrouper(string assetPath)
{
@@ -72,7 +72,6 @@ namespace YooAsset
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = loader.BundleFileInfo.BundleName;
bundleInfo.Version = loader.BundleFileInfo.Version;
bundleInfo.RefCount = loader.RefCount;
bundleInfo.Status = loader.Status;
output.Add(bundleInfo);

View File

@@ -15,6 +15,7 @@ namespace YooAsset
private readonly Vector3 _position;
private readonly Quaternion _rotation;
private readonly Transform _parent;
private readonly bool _setPositionRotation;
private ESteps _steps = ESteps.None;
/// <summary>
@@ -23,12 +24,13 @@ namespace YooAsset
public GameObject Result = null;
internal InstantiateOperation(AssetOperationHandle handle, Vector3 position, Quaternion rotation, Transform parent)
internal InstantiateOperation(AssetOperationHandle handle, Vector3 position, Quaternion rotation, Transform parent, bool setPositionRotation)
{
_handle = handle;
_position = position;
_rotation = rotation;
_parent = parent;
_setPositionRotation = setPositionRotation;
}
internal override void Start()
{
@@ -46,18 +48,31 @@ namespace YooAsset
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle)} is invalid.";
return;
}
if (_handle.AssetObject == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle.AssetObject)} is null.";
return;
}
if (_parent == null)
Result = Object.Instantiate(_handle.AssetObject as GameObject, _position, _rotation);
if(_setPositionRotation)
{
if (_parent == null)
Result = Object.Instantiate(_handle.AssetObject as GameObject, _position, _rotation);
else
Result = Object.Instantiate(_handle.AssetObject as GameObject, _position, _rotation, _parent);
}
else
Result = Object.Instantiate(_handle.AssetObject as GameObject, _position, _rotation, _parent);
{
if (_parent == null)
Result = Object.Instantiate(_handle.AssetObject as GameObject);
else
Result = Object.Instantiate(_handle.AssetObject as GameObject, _parent);
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;

View File

@@ -2,39 +2,70 @@
namespace YooAsset
{
public class RawFileOperation : AsyncOperationBase
/// <summary>
/// 原生文件操作
/// </summary>
public abstract class RawFileOperation : AsyncOperationBase
{
protected readonly BundleInfo _bundleInfo;
/// <summary>
/// 原生文件的拷贝路径
/// </summary>
public string CopyPath { private set; get; }
internal RawFileOperation(BundleInfo bundleInfo, string copyPath)
{
_bundleInfo = bundleInfo;
CopyPath = copyPath;
}
/// <summary>
/// 原生文件的缓存路径
/// </summary>
public abstract string GetCachePath();
/// <summary>
/// 获取原生文件的二进制数据
/// </summary>
public byte[] GetFileData()
{
string filePath = GetCachePath();
if (File.Exists(filePath) == false)
return null;
return File.ReadAllBytes(filePath);
}
/// <summary>
/// 获取原生文件的文本数据
/// </summary>
public string GetFileText()
{
string filePath = GetCachePath();
if (File.Exists(filePath) == false)
return string.Empty;
return File.ReadAllText(filePath, System.Text.Encoding.UTF8);
}
}
/// <summary>
/// 编辑器下模拟运行的原生文件操作
/// </summary>
internal sealed class EditorPlayModeRawFileOperation : RawFileOperation
{
private enum ESteps
{
None,
Prepare,
DownloadFromWeb,
CheckDownloadFromWeb,
CheckFile,
DownloadFromApk,
CheckDownloadFromApk,
CheckAndCopyFile,
Done,
}
private readonly BundleInfo _bundleInfo;
private readonly string _savePath;
private ESteps _steps = ESteps.None;
private DownloaderBase _downloader;
private UnityWebFileRequester _fileRequester;
/// <summary>
/// 原生文件的存储路径
/// </summary>
public string SavePath
internal EditorPlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath)
{
get { return _savePath; }
}
internal RawFileOperation(BundleInfo bundleInfo, string savePath)
{
_bundleInfo = bundleInfo;
_savePath = savePath;
}
internal override void Start()
{
@@ -48,19 +79,250 @@ namespace YooAsset
// 1. 准备工作
if (_steps == ESteps.Prepare)
{
// 检测加载地址是否为空
if (string.IsNullOrEmpty(_bundleInfo.LocalPath))
if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.None)
{
_steps = ESteps.CheckAndCopyFile;
return; // 模拟实现异步操作
}
else
{
throw new System.NotImplementedException(_bundleInfo.LoadMode.ToString());
}
}
// 2. 检测并拷贝原生文件
if (_steps == ESteps.CheckAndCopyFile)
{
// 如果不需要保存文件
if (string.IsNullOrEmpty(CopyPath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Local path is null or empty.";
Status = EOperationStatus.Succeed;
return;
}
if (string.IsNullOrEmpty(_bundleInfo.RemoteMainURL))
_steps = ESteps.CheckFile;
// 如果原生文件已经存在,则将其删除
if (File.Exists(CopyPath))
{
File.Delete(CopyPath);
}
try
{
FileUtility.CreateFileDirectory(CopyPath);
File.Copy(GetCachePath(), CopyPath, true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
catch (System.Exception e)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = e.ToString();
}
}
}
/// <summary>
/// 原生文件的缓存路径
/// </summary>
public override string GetCachePath()
{
if (_bundleInfo == null)
return string.Empty;
return _bundleInfo.BundleName;
}
}
/// <summary>
/// 离线模式的原生文件操作
/// </summary>
internal sealed class OfflinePlayModeRawFileOperation : RawFileOperation
{
private enum ESteps
{
None,
Prepare,
DownloadFromApk,
CheckDownloadFromApk,
CheckAndCopyFile,
Done,
}
private ESteps _steps = ESteps.None;
private UnityWebFileRequester _fileRequester;
public OfflinePlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath)
{
}
internal override void Start()
{
_steps = ESteps.Prepare;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 1. 准备工作
if (_steps == ESteps.Prepare)
{
if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.None)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Bundle info is invalid : {_bundleInfo.BundleName}";
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.DownloadFromApk;
}
else
{
throw new System.NotImplementedException(_bundleInfo.LoadMode.ToString());
}
}
// 2. 从APK拷贝文件
if (_steps == ESteps.DownloadFromApk)
{
string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath());
_fileRequester = new UnityWebFileRequester();
_fileRequester.SendRequest(downloadURL, GetCachePath());
_steps = ESteps.CheckDownloadFromApk;
}
// 3. 检测APK拷贝文件结果
if (_steps == ESteps.CheckDownloadFromApk)
{
if (_fileRequester.IsDone() == false)
return;
if (_fileRequester.HasError())
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _fileRequester.GetError();
}
else
{
_steps = ESteps.CheckAndCopyFile;
}
_fileRequester.Dispose();
}
// 4. 检测并拷贝原生文件
if (_steps == ESteps.CheckAndCopyFile)
{
// 如果不需要保存文件
if (string.IsNullOrEmpty(CopyPath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
return;
}
// 如果原生文件已经存在,则验证其完整性
if (File.Exists(CopyPath))
{
bool result = DownloadSystem.CheckContentIntegrity(CopyPath, _bundleInfo.SizeBytes, _bundleInfo.CRC);
if (result)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
return;
}
else
{
File.Delete(CopyPath);
}
}
try
{
FileUtility.CreateFileDirectory(CopyPath);
File.Copy(GetCachePath(), CopyPath, true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
catch (System.Exception e)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = e.ToString();
}
}
}
/// <summary>
/// 原生文件的缓存路径
/// </summary>
public override string GetCachePath()
{
if (_bundleInfo == null)
return string.Empty;
return _bundleInfo.GetCacheLoadPath();
}
}
/// <summary>
/// 网络模式的原生文件操作
/// </summary>
internal sealed class HostPlayModeRawFileOperation : RawFileOperation
{
private enum ESteps
{
None,
Prepare,
DownloadFromWeb,
CheckDownloadFromWeb,
DownloadFromApk,
CheckDownloadFromApk,
CheckAndCopyFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _downloader;
private UnityWebFileRequester _fileRequester;
internal HostPlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath)
{
}
internal override void Start()
{
_steps = ESteps.Prepare;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 1. 准备工作
if (_steps == ESteps.Prepare)
{
if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.None)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Bundle info is invalid : {_bundleInfo.BundleName}";
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.DownloadFromWeb;
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.DownloadFromApk;
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.CheckAndCopyFile;
}
else
{
throw new System.NotImplementedException(_bundleInfo.LoadMode.ToString());
}
}
// 2. 从服务器下载
@@ -85,65 +347,20 @@ namespace YooAsset
}
else
{
// 注意:当文件更新之后,需要删除旧文件
if (File.Exists(_savePath))
File.Delete(_savePath);
_steps = ESteps.CheckFile;
_steps = ESteps.CheckAndCopyFile;
}
}
// 4. 检测文件
if (_steps == ESteps.CheckFile)
{
// 注意:如果原生文件已经存在,则验证其完整性
if (File.Exists(_savePath))
{
bool result = DownloadSystem.CheckContentIntegrity(_savePath, _bundleInfo.SizeBytes, _bundleInfo.CRC);
if (result)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
return;
}
else
{
File.Delete(_savePath);
}
}
if (_bundleInfo.IsBuildinJarFile())
{
_steps = ESteps.DownloadFromApk;
}
else
{
try
{
File.Copy(_bundleInfo.LocalPath, _savePath, true);
}
catch (System.Exception e)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = e.ToString();
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
// 5. 从APK拷贝文件
// 4. 从APK拷贝文件
if (_steps == ESteps.DownloadFromApk)
{
string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.LocalPath);
string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath());
_fileRequester = new UnityWebFileRequester();
_fileRequester.SendRequest(downloadURL, _savePath);
_fileRequester.SendRequest(downloadURL, GetCachePath());
_steps = ESteps.CheckDownloadFromApk;
}
// 6. 检测APK拷贝文件结果
// 5. 检测APK拷贝文件结果
if (_steps == ESteps.CheckDownloadFromApk)
{
if (_fileRequester.IsDone() == false)
@@ -157,32 +374,62 @@ namespace YooAsset
}
else
{
_steps = ESteps.CheckAndCopyFile;
}
_fileRequester.Dispose();
}
// 6. 检测并拷贝原生文件
if (_steps == ESteps.CheckAndCopyFile)
{
// 如果不需要保存文件
if (string.IsNullOrEmpty(CopyPath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
return;
}
// 如果原生文件已经存在,则验证其完整性
if (File.Exists(CopyPath))
{
bool result = DownloadSystem.CheckContentIntegrity(CopyPath, _bundleInfo.SizeBytes, _bundleInfo.CRC);
if (result)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
return;
}
else
{
File.Delete(CopyPath);
}
}
try
{
FileUtility.CreateFileDirectory(CopyPath);
File.Copy(GetCachePath(), CopyPath, true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
_fileRequester.Dispose();
catch (System.Exception e)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = e.ToString();
}
}
}
/// <summary>
/// 获取原生文件的二进制数据
/// 原生文件的缓存路径
/// </summary>
public byte[] GetFileData()
public override string GetCachePath()
{
if (File.Exists(_savePath) == false)
return null;
return File.ReadAllBytes(_savePath);
}
/// <summary>
/// 获取原生文件的文本数据
/// </summary>
public string GetFileText()
{
if (File.Exists(_savePath) == false)
if (_bundleInfo == null)
return string.Empty;
return File.ReadAllText(_savePath, System.Text.Encoding.UTF8);
return _bundleInfo.GetCacheLoadPath();
}
}
}

View File

@@ -12,7 +12,6 @@ namespace YooAsset
{
Normal,
Error,
Skip,
}
private enum ESteps
{
@@ -40,10 +39,6 @@ namespace YooAsset
}
}
internal UnloadSceneOperation()
{
_flag = EFlag.Skip;
}
internal UnloadSceneOperation(string error)
{
_flag = EFlag.Error;
@@ -60,11 +55,6 @@ namespace YooAsset
{
_steps = ESteps.UnLoad;
}
else if (_flag == EFlag.Skip)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else if (_flag == EFlag.Error)
{
_steps = ESteps.Done;

View File

@@ -5,7 +5,7 @@ namespace YooAsset
{
internal abstract class BundledProvider : ProviderBase
{
protected AssetBundleLoader OwnerBundle { private set; get; }
protected AssetBundleLoaderBase OwnerBundle { private set; get; }
protected DependAssetBundleGrouper DependBundles { private set; get; }
public BundledProvider(string assetPath, System.Type assetType) : base(assetPath, assetType)
@@ -40,7 +40,6 @@ namespace YooAsset
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = OwnerBundle.BundleFileInfo.BundleName;
bundleInfo.Version = OwnerBundle.BundleFileInfo.Version;
bundleInfo.RefCount = OwnerBundle.RefCount;
bundleInfo.Status = OwnerBundle.Status;
output.Add(bundleInfo);

View File

@@ -1,5 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace YooAsset
{
@@ -197,38 +199,62 @@ namespace YooAsset
/// <summary>
/// 异步操作任务
/// </summary>
public System.Threading.Tasks.Task<object> Task
public Task Task
{
get
{
var handle = WaitHandle;
return System.Threading.Tasks.Task.Factory.StartNew(o =>
if (_taskCompletionSource == null)
{
handle.WaitOne();
return AssetObject as object;
}, this);
_taskCompletionSource = new TaskCompletionSource<object>();
if (IsDone)
_taskCompletionSource.SetResult(null);
}
return _taskCompletionSource.Task;
}
}
#region
private System.Threading.EventWaitHandle _waitHandle;
private System.Threading.WaitHandle WaitHandle
{
get
{
if (_waitHandle == null)
_waitHandle = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
_waitHandle.Reset();
return _waitHandle;
}
}
private TaskCompletionSource<object> _taskCompletionSource;
protected void InvokeCompletion()
{
foreach (var handle in _handles)
// 注意:创建临时列表是为了防止外部逻辑在回调函数内创建或者释放资源句柄。
List<OperationHandleBase> tempers = new List<OperationHandleBase>(_handles);
foreach (var hande in tempers)
{
handle.InvokeCallback();
if (hande.IsValid)
{
hande.InvokeCallback();
}
}
_waitHandle?.Set();
if (_taskCompletionSource != null)
_taskCompletionSource.TrySetResult(null);
}
#endregion
#region
/// <summary>
/// 出生的场景
/// </summary>
public string SpawnScene = string.Empty;
/// <summary>
/// 出生的时间
/// </summary>
public string SpawnTime = string.Empty;
[Conditional("DEBUG")]
public void InitSpawnDebugInfo()
{
SpawnScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; ;
SpawnTime = SpawnTimeToString(UnityEngine.Time.realtimeSinceStartup);
}
private string SpawnTimeToString(float spawnTime)
{
float h = UnityEngine.Mathf.FloorToInt(spawnTime / 3600f);
float m = UnityEngine.Mathf.FloorToInt(spawnTime / 60f - h * 60f);
float s = UnityEngine.Mathf.FloorToInt(spawnTime - m * 60f - h * 3600f);
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
}
#endregion
}

View File

@@ -8,11 +8,6 @@ namespace YooAsset
/// </summary>
public string BundleName { set; get; }
/// <summary>
/// 资源版本
/// </summary>
public int Version { set; get; }
/// <summary>
/// 引用计数
/// </summary>
@@ -21,6 +16,6 @@ namespace YooAsset
/// <summary>
/// 加载状态
/// </summary>
public AssetBundleLoader.EStatus Status { set; get; }
public AssetBundleLoaderBase.EStatus Status { set; get; }
}
}

View File

@@ -11,6 +11,16 @@ namespace YooAsset
/// </summary>
public string AssetPath { set; get; }
/// <summary>
/// 资源出生的场景
/// </summary>
public string SpawnScene { set; get; }
/// <summary>
/// 资源出生的时间
/// </summary>
public string SpawnTime { set; get; }
/// <summary>
/// 引用计数
/// </summary>

View File

@@ -84,7 +84,7 @@ namespace YooAsset
// 创建新的下载器
{
YooLogger.Log($"Beginning to download file : {bundleInfo.BundleName} URL : {bundleInfo.RemoteMainURL}");
FileUtility.CreateFileDirectory(bundleInfo.LocalPath);
FileUtility.CreateFileDirectory(bundleInfo.GetCacheLoadPath());
DownloaderBase newDownloader;
if (bundleInfo.SizeBytes >= _breakpointResumeFileSize)
newDownloader = new HttpDownloader(bundleInfo);
@@ -146,7 +146,7 @@ namespace YooAsset
// 验证文件完整性
public static bool CheckContentIntegrity(BundleInfo bundleInfo)
{
return CheckContentIntegrity(bundleInfo.LocalPath, bundleInfo.SizeBytes, bundleInfo.CRC);
return CheckContentIntegrity(bundleInfo.GetCacheLoadPath(), bundleInfo.SizeBytes, bundleInfo.CRC);
}
public static bool CheckContentIntegrity(PatchBundle patchBundle)
{

View File

@@ -50,9 +50,6 @@ namespace YooAsset
}
public void SendRequest(int failedTryAgain, int timeout)
{
if (string.IsNullOrEmpty(_bundleInfo.LocalPath))
throw new System.ArgumentNullException();
if (_steps == ESteps.None)
{
_failedTryAgain = failedTryAgain;
@@ -62,7 +59,7 @@ namespace YooAsset
}
public abstract void Update();
public abstract void Abort();
/// <summary>
/// 获取网络请求地址
/// </summary>

View File

@@ -42,7 +42,7 @@ namespace YooAsset
_requestURL = GetRequestURL();
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
DownloadHandlerFile handler = new DownloadHandlerFile(_bundleInfo.LocalPath);
DownloadHandlerFile handler = new DownloadHandlerFile(_bundleInfo.GetCacheLoadPath());
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
@@ -97,8 +97,9 @@ namespace YooAsset
{
ReportError();
if (File.Exists(_bundleInfo.LocalPath))
File.Delete(_bundleInfo.LocalPath);
string cacheFilePath = _bundleInfo.GetCacheLoadPath();
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
// 失败后重新尝试
if (_failedTryAgain > 0)

View File

@@ -197,7 +197,7 @@ namespace YooAsset
_requestURL = GetRequestURL();
_threadDownloader = new ThreadDownloader();
_threadDownloader.Run(_requestURL, _bundleInfo.LocalPath, _bundleInfo.Hash, _bundleInfo.CRC, _bundleInfo.SizeBytes, _timeout);
_threadDownloader.Run(_requestURL, _bundleInfo.GetCacheLoadPath(), _bundleInfo.Hash, _bundleInfo.CRC, _bundleInfo.SizeBytes, _timeout);
_steps = ESteps.CheckDownload;
}

View File

@@ -3,18 +3,25 @@ namespace YooAsset
{
public class BundleInfo
{
internal enum ELoadMode
{
None,
LoadFromStreaming,
LoadFromCache,
LoadFromRemote,
}
private readonly PatchBundle _patchBundle;
internal readonly ELoadMode LoadMode;
private string _streamingPath;
private string _cachePath;
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName { private set; get; }
/// <summary>
/// 本地存储的路径
/// </summary>
public string LocalPath { private set; get; }
/// <summary>
/// 远端下载地址
/// </summary>
@@ -67,20 +74,6 @@ namespace YooAsset
}
}
/// <summary>
/// 资源版本
/// </summary>
public int Version
{
get
{
if (_patchBundle == null)
return 0;
else
return _patchBundle.Version;
}
}
/// <summary>
/// 是否为加密文件
/// </summary>
@@ -110,30 +103,57 @@ namespace YooAsset
}
/// <summary>
/// 获取流文件夹的加载路径
/// </summary>
public string GetStreamingLoadPath()
{
if (_patchBundle == null)
return string.Empty;
if (string.IsNullOrEmpty(_streamingPath))
_streamingPath = PathHelper.MakeStreamingLoadPath(_patchBundle.Hash);
return _streamingPath;
}
/// <summary>
/// 获取缓存文件夹的加载路径
/// </summary>
public string GetCacheLoadPath()
{
if (_patchBundle == null)
return string.Empty;
if (string.IsNullOrEmpty(_cachePath))
_cachePath = SandboxHelper.MakeSandboxCacheFilePath(_patchBundle.Hash);
return _cachePath;
}
private BundleInfo()
{
}
internal BundleInfo(PatchBundle patchBundle, string localPath, string mainURL, string fallbackURL)
internal BundleInfo(PatchBundle patchBundle, ELoadMode loadMode, string mainURL, string fallbackURL)
{
_patchBundle = patchBundle;
LoadMode = loadMode;
BundleName = patchBundle.BundleName;
LocalPath = localPath;
RemoteMainURL = mainURL;
RemoteFallbackURL = fallbackURL;
}
internal BundleInfo(PatchBundle patchBundle, string localPath)
internal BundleInfo(PatchBundle patchBundle, ELoadMode loadMode)
{
_patchBundle = patchBundle;
LoadMode = loadMode;
BundleName = patchBundle.BundleName;
LocalPath = localPath;
RemoteMainURL = string.Empty;
RemoteFallbackURL = string.Empty;
}
internal BundleInfo(string bundleName, string localPath)
internal BundleInfo(string bundleName)
{
_patchBundle = null;
LoadMode = ELoadMode.None;
BundleName = bundleName;
LocalPath = localPath;
RemoteMainURL = string.Empty;
RemoteFallbackURL = string.Empty;
}
@@ -141,9 +161,9 @@ namespace YooAsset
/// <summary>
/// 是否为JAR包内文件
/// </summary>
public bool IsBuildinJarFile()
public static bool IsBuildinJarFile(string streamingPath)
{
return LocalPath.StartsWith("jar:");
return streamingPath.StartsWith("jar:");
}
}
}

View File

@@ -1,6 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
@@ -15,7 +14,7 @@ namespace YooAsset
/// <summary>
/// 编辑器下模拟运行的初始化操作
/// </summary>
internal class EditorModeInitializationOperation : InitializationOperation
internal sealed class EditorPlayModeInitializationOperation : InitializationOperation
{
internal override void Start()
{
@@ -29,20 +28,18 @@ namespace YooAsset
/// <summary>
/// 离线模式的初始化操作
/// </summary>
internal class OfflinePlayModeInitializationOperation : InitializationOperation
internal sealed class OfflinePlayModeInitializationOperation : InitializationOperation
{
private enum ESteps
{
None,
LoadAppManifest,
CheckAppManifest,
Update,
Done,
}
private OfflinePlayModeImpl _impl;
private readonly OfflinePlayModeImpl _impl;
private readonly AppManifestLoader _appManifestLoader = new AppManifestLoader();
private ESteps _steps = ESteps.None;
private UnityWebDataRequester _downloader;
private string _downloadURL;
internal OfflinePlayModeInitializationOperation(OfflinePlayModeImpl impl)
{
@@ -50,41 +47,32 @@ namespace YooAsset
}
internal override void Start()
{
_steps = ESteps.LoadAppManifest;
_steps = ESteps.Update;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadAppManifest)
if (_steps == ESteps.Update)
{
string filePath = PathHelper.MakeStreamingLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
_downloadURL = PathHelper.ConvertToWWWPath(filePath);
_downloader = new UnityWebDataRequester();
_downloader.SendRequest(_downloadURL);
_steps = ESteps.CheckAppManifest;
}
if (_steps == ESteps.CheckAppManifest)
{
if (_downloader.IsDone() == false)
_appManifestLoader.Update();
if (_appManifestLoader.IsDone() == false)
return;
if (_downloader.HasError())
{
Error = _downloader.GetError();
_downloader.Dispose();
if (_appManifestLoader.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
throw new System.Exception($"Fatal error : Failed load application patch manifest file : {_downloadURL}");
Error = _appManifestLoader.Error;
throw new System.Exception($"FATAL : {_appManifestLoader.Error}");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
_impl.AppPatchManifest = _appManifestLoader.Result;
}
// 解析APP里的补丁清单
_impl.AppPatchManifest = PatchManifest.Deserialize(_downloader.GetText());
_downloader.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
@@ -92,22 +80,19 @@ namespace YooAsset
/// <summary>
/// 网络模式的初始化操作
/// </summary>
internal class HostPlayModeInitializationOperation : InitializationOperation
internal sealed class HostPlayModeInitializationOperation : InitializationOperation
{
private enum ESteps
{
None,
InitCache,
LoadAppManifest,
CheckAppManifest,
LoadSandboxManifest,
Update,
Done,
}
private HostPlayModeImpl _impl;
private readonly HostPlayModeImpl _impl;
private readonly AppManifestLoader _appManifestLoader = new AppManifestLoader();
private ESteps _steps = ESteps.None;
private UnityWebDataRequester _downloader;
private string _downloadURL;
internal HostPlayModeInitializationOperation(HostPlayModeImpl impl)
{
@@ -137,60 +122,137 @@ namespace YooAsset
SandboxHelper.DeleteSandboxCacheFolder();
}
// 删除清单文件
SandboxHelper.DeleteSandboxPatchManifestFile();
// 更新缓存文件
PatchCache.UpdateCache();
}
_steps = ESteps.LoadAppManifest;
_steps = ESteps.Update;
}
if (_steps == ESteps.Update)
{
_appManifestLoader.Update();
if (_appManifestLoader.IsDone() == false)
return;
if (_appManifestLoader.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _appManifestLoader.Error;
throw new System.Exception($"FATAL : {_appManifestLoader.Error}");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
_impl.AppPatchManifest = _appManifestLoader.Result;
_impl.LocalPatchManifest = _appManifestLoader.Result;
}
}
}
}
/// <summary>
/// 内置补丁清单加载器
/// </summary>
internal class AppManifestLoader
{
private enum ESteps
{
LoadStaticVersion,
CheckStaticVersion,
LoadAppManifest,
CheckAppManifest,
Succeed,
Failed,
}
private ESteps _steps = ESteps.LoadStaticVersion;
private UnityWebDataRequester _downloader1;
private UnityWebDataRequester _downloader2;
private int _staticVersion = 0;
/// <summary>
/// 错误日志
/// </summary>
public string Error { private set; get; }
/// <summary>
/// 补丁清单
/// </summary>
public PatchManifest Result { private set; get; }
/// <summary>
/// 是否已经完成
/// </summary>
public bool IsDone()
{
if (_steps == ESteps.Succeed || _steps == ESteps.Failed)
return true;
else
return false;
}
public void Update()
{
if (IsDone())
return;
if (_steps == ESteps.LoadStaticVersion)
{
YooLogger.Log($"Load application static version.");
string filePath = PathHelper.MakeStreamingLoadPath(YooAssetSettings.VersionFileName);
string url = PathHelper.ConvertToWWWPath(filePath);
_downloader1 = new UnityWebDataRequester();
_downloader1.SendRequest(url);
_steps = ESteps.CheckStaticVersion;
}
if (_steps == ESteps.CheckStaticVersion)
{
if (_downloader1.IsDone() == false)
return;
if (_downloader1.HasError())
{
Error = _downloader1.GetError();
_steps = ESteps.Failed;
}
else
{
_staticVersion = int.Parse(_downloader1.GetText());
_steps = ESteps.LoadAppManifest;
}
_downloader1.Dispose();
}
if (_steps == ESteps.LoadAppManifest)
{
// 加载APP内的补丁清单
YooLogger.Log($"Load application patch manifest.");
string filePath = PathHelper.MakeStreamingLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
_downloadURL = PathHelper.ConvertToWWWPath(filePath);
_downloader = new UnityWebDataRequester();
_downloader.SendRequest(_downloadURL);
string filePath = PathHelper.MakeStreamingLoadPath(YooAssetSettingsData.GetPatchManifestFileName(_staticVersion));
string url = PathHelper.ConvertToWWWPath(filePath);
_downloader2 = new UnityWebDataRequester();
_downloader2.SendRequest(url);
_steps = ESteps.CheckAppManifest;
}
if (_steps == ESteps.CheckAppManifest)
{
if (_downloader.IsDone() == false)
if (_downloader2.IsDone() == false)
return;
if (_downloader.HasError())
if (_downloader2.HasError())
{
Error = _downloader.GetError();
_downloader.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
throw new System.Exception($"Fatal error : Failed load application patch manifest file : {_downloadURL}");
Error = _downloader2.GetError();
_steps = ESteps.Failed;
}
// 解析补丁清单
string jsonData = _downloader.GetText();
_impl.AppPatchManifest = PatchManifest.Deserialize(jsonData);
_impl.LocalPatchManifest = _impl.AppPatchManifest;
_downloader.Dispose();
_steps = ESteps.LoadSandboxManifest;
}
if (_steps == ESteps.LoadSandboxManifest)
{
// 加载沙盒内的补丁清单
if (SandboxHelper.CheckSandboxPatchManifestFileExist())
else
{
YooLogger.Log($"Load sandbox patch manifest.");
string filePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
string jsonData = File.ReadAllText(filePath);
_impl.LocalPatchManifest = PatchManifest.Deserialize(jsonData);
// 解析APP里的补丁清单
Result = PatchManifest.Deserialize(_downloader2.GetText());
_steps = ESteps.Succeed;
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
_downloader2.Dispose();
}
}
}

View File

@@ -16,7 +16,7 @@ namespace YooAsset
/// <summary>
/// 编辑器下模拟运行的更新清单操作
/// </summary>
internal class EditorModeUpdateManifestOperation : UpdateManifestOperation
internal sealed class EditorPlayModeUpdateManifestOperation : UpdateManifestOperation
{
internal override void Start()
{
@@ -30,7 +30,7 @@ namespace YooAsset
/// <summary>
/// 离线模式的更新清单操作
/// </summary>
internal class OfflinePlayModeUpdateManifestOperation : UpdateManifestOperation
internal sealed class OfflinePlayModeUpdateManifestOperation : UpdateManifestOperation
{
internal override void Start()
{
@@ -44,7 +44,7 @@ namespace YooAsset
/// <summary>
/// 网络模式的更新清单操作
/// </summary>
internal class HostPlayModeUpdateManifestOperation : UpdateManifestOperation
internal sealed class HostPlayModeUpdateManifestOperation : UpdateManifestOperation
{
private enum ESteps
{
@@ -59,7 +59,6 @@ namespace YooAsset
}
private static int RequestCount = 0;
private readonly HostPlayModeImpl _impl;
private readonly int _updateResourceVersion;
private readonly int _timeout;
@@ -78,15 +77,6 @@ namespace YooAsset
{
RequestCount++;
_steps = ESteps.LoadWebManifestHash;
if (_impl.IgnoreResourceVersion && _updateResourceVersion > 0)
{
YooLogger.Warning($"Update resource version {_updateResourceVersion} is invalid when ignore resource version.");
}
else
{
YooLogger.Log($"Update patch manifest : update resource version is {_updateResourceVersion}");
}
}
internal override void Update()
{
@@ -95,7 +85,7 @@ namespace YooAsset
if (_steps == ESteps.LoadWebManifestHash)
{
string webURL = GetPatchManifestRequestURL(_updateResourceVersion, YooAssetSettingsData.Setting.PatchManifestHashFileName);
string webURL = GetPatchManifestRequestURL(YooAssetSettingsData.GetPatchManifestHashFileName(_updateResourceVersion));
YooLogger.Log($"Beginning to request patch manifest hash : {webURL}");
_downloaderHash = new UnityWebDataRequester();
_downloaderHash.SendRequest(webURL, _timeout);
@@ -107,37 +97,37 @@ namespace YooAsset
if (_downloaderHash.IsDone() == false)
return;
// Check fatal
// Check error
if (_downloaderHash.HasError())
{
Error = _downloaderHash.GetError();
_downloaderHash.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
return;
}
// 获取补丁清单文件的哈希值
string webManifestHash = _downloaderHash.GetText();
_downloaderHash.Dispose();
// 如果补丁清单文件的哈希值相同
string currentFileHash = SandboxHelper.GetSandboxPatchManifestFileHash();
if (currentFileHash == webManifestHash)
{
YooLogger.Log($"Patch manifest file hash is not change : {webManifestHash}");
_steps = ESteps.InitPrepareCache;
Error = _downloaderHash.GetError();
}
else
{
YooLogger.Log($"Patch manifest hash is change : {webManifestHash} -> {currentFileHash}");
_steps = ESteps.LoadWebManifest;
string webManifestHash = _downloaderHash.GetText();
string cachedManifestHash = GetSandboxPatchManifestFileHash(_updateResourceVersion);
// 如果补丁清单文件的哈希值相同
if (cachedManifestHash == webManifestHash)
{
YooLogger.Log($"Patch manifest file hash is not change : {webManifestHash}");
LoadSandboxPatchManifest(_updateResourceVersion);
_steps = ESteps.InitPrepareCache;
}
else
{
YooLogger.Log($"Patch manifest hash is change : {webManifestHash} -> {cachedManifestHash}");
_steps = ESteps.LoadWebManifest;
}
}
_downloaderHash.Dispose();
}
if (_steps == ESteps.LoadWebManifest)
{
string webURL = GetPatchManifestRequestURL(_updateResourceVersion, YooAssetSettingsData.Setting.PatchManifestFileName);
string webURL = GetPatchManifestRequestURL(YooAssetSettingsData.GetPatchManifestFileName(_updateResourceVersion));
YooLogger.Log($"Beginning to request patch manifest : {webURL}");
_downloaderManifest = new UnityWebDataRequester();
_downloaderManifest.SendRequest(webURL, _timeout);
@@ -149,20 +139,28 @@ namespace YooAsset
if (_downloaderManifest.IsDone() == false)
return;
// Check fatal
// Check error
if (_downloaderManifest.HasError())
{
Error = _downloaderManifest.GetError();
_downloaderManifest.Dispose();
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
return;
Error = _downloaderManifest.GetError();
}
else
{
// 解析补丁清单
if (ParseAndSaveRemotePatchManifest(_updateResourceVersion, _downloaderManifest.GetText()))
{
_steps = ESteps.InitPrepareCache;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"URL : {_downloaderManifest.URL} Error : remote patch manifest content is invalid";
}
}
// 解析补丁清单
ParseAndSaveRemotePatchManifest(_downloaderManifest.GetText());
_downloaderManifest.Dispose();
_steps = ESteps.InitPrepareCache;
}
if (_steps == ESteps.InitPrepareCache)
@@ -184,30 +182,58 @@ namespace YooAsset
}
}
private string GetPatchManifestRequestURL(int updateResourceVersion, string fileName)
private string GetPatchManifestRequestURL(string fileName)
{
string url;
// 轮流返回请求地址
if (RequestCount % 2 == 0)
url = _impl.GetPatchDownloadFallbackURL(updateResourceVersion, fileName);
return _impl.GetPatchDownloadFallbackURL(fileName);
else
url = _impl.GetPatchDownloadMainURL(updateResourceVersion, fileName);
// 注意在URL末尾添加时间戳
if (_impl.IgnoreResourceVersion)
url = $"{url}?{System.DateTime.UtcNow.Ticks}";
return url;
return _impl.GetPatchDownloadMainURL(fileName);
}
private void ParseAndSaveRemotePatchManifest(string content)
{
_impl.LocalPatchManifest = PatchManifest.Deserialize(content);
// 注意:这里会覆盖掉沙盒内的补丁清单文件
YooLogger.Log("Save remote patch manifest file.");
string savePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
PatchManifest.Serialize(savePath, _impl.LocalPatchManifest);
/// <summary>
/// 解析并保存远端请求的补丁清单
/// </summary>
private bool ParseAndSaveRemotePatchManifest(int updateResourceVersion, string content)
{
try
{
_impl.LocalPatchManifest = PatchManifest.Deserialize(content);
YooLogger.Log("Save remote patch manifest file.");
string savePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.GetPatchManifestFileName(updateResourceVersion));
PatchManifest.Serialize(savePath, _impl.LocalPatchManifest);
return true;
}
catch (Exception e)
{
YooLogger.Warning(e.ToString());
return false;
}
}
/// <summary>
/// 加载沙盒内的补丁清单
/// </summary>
private void LoadSandboxPatchManifest(int updateResourceVersion)
{
YooLogger.Log("Load sandbox patch manifest file.");
string filePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.GetPatchManifestFileName(updateResourceVersion));
string jsonData = File.ReadAllText(filePath);
_impl.LocalPatchManifest = PatchManifest.Deserialize(jsonData);
}
/// <summary>
/// 获取沙盒内补丁清单文件的哈希值
/// 注意:如果沙盒内补丁清单文件不存在,返回空字符串
/// </summary>
private string GetSandboxPatchManifestFileHash(int updateResourceVersion)
{
string filePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.GetPatchManifestFileName(updateResourceVersion));
if (File.Exists(filePath))
return HashUtility.FileMD5(filePath);
else
return string.Empty;
}
#region 线

View File

@@ -0,0 +1,132 @@
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 更新静态版本操作
/// </summary>
public abstract class UpdateStaticVersionOperation : AsyncOperationBase
{
/// <summary>
/// 资源版本号
/// </summary>
public int ResourceVersion { protected set; get; } = 0;
}
/// <summary>
/// 编辑器下模拟运行的更新静态版本操作
/// </summary>
internal sealed class EditorPlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation
{
internal override void Start()
{
Status = EOperationStatus.Succeed;
}
internal override void Update()
{
}
}
/// <summary>
/// 离线模式的更新静态版本操作
/// </summary>
internal sealed class OfflinePlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation
{
internal override void Start()
{
Status = EOperationStatus.Succeed;
}
internal override void Update()
{
}
}
/// <summary>
/// 网络模式的更新静态版本操作
/// </summary>
internal sealed class HostPlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation
{
private enum ESteps
{
None,
LoadStaticVersion,
CheckStaticVersion,
Done,
}
private static int RequestCount = 0;
private readonly HostPlayModeImpl _impl;
private readonly int _timeout;
private ESteps _steps = ESteps.None;
private UnityWebDataRequester _downloader;
internal HostPlayModeUpdateStaticVersionOperation(HostPlayModeImpl impl, int timeout)
{
_impl = impl;
_timeout = timeout;
}
internal override void Start()
{
RequestCount++;
_steps = ESteps.LoadStaticVersion;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadStaticVersion)
{
string webURL = GetStaticVersionRequestURL(YooAssetSettings.VersionFileName);
YooLogger.Log($"Beginning to request static version : {webURL}");
_downloader = new UnityWebDataRequester();
_downloader.SendRequest(webURL, _timeout);
_steps = ESteps.CheckStaticVersion;
}
if (_steps == ESteps.CheckStaticVersion)
{
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloader.GetError();
}
else
{
if (int.TryParse(_downloader.GetText(), out int value))
{
ResourceVersion = value;
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"URL : {_downloader.URL} Error : static version content is invalid.";
}
}
_downloader.Dispose();
}
}
private string GetStaticVersionRequestURL(string fileName)
{
string url;
// 轮流返回请求地址
if (RequestCount % 2 == 0)
url = _impl.GetPatchDownloadFallbackURL(fileName);
else
url = _impl.GetPatchDownloadMainURL(fileName);
// 注意在URL末尾添加时间戳
return $"{url}?{System.DateTime.UtcNow.Ticks}";
}
}
}

View File

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

View File

@@ -26,11 +26,6 @@ namespace YooAsset
/// </summary>
public long SizeBytes;
/// <summary>
/// 文件版本
/// </summary>
public int Version;
/// <summary>
/// Tags
/// </summary>
@@ -59,13 +54,12 @@ namespace YooAsset
public PatchBundle(string bundleName, string hash, string crc, long sizeBytes, int version, string[] tags)
public PatchBundle(string bundleName, string hash, string crc, long sizeBytes, string[] tags)
{
BundleName = bundleName;
Hash = hash;
CRC = crc;
SizeBytes = sizeBytes;
Version = version;
Tags = tags;
}

View File

@@ -20,15 +20,16 @@ namespace YooAsset
public static PatchCache LoadCache()
{
if (SandboxHelper.CheckSandboxCacheFileExist())
{
YooLogger.Log("Load patch cache from disk.");
{
string filePath = SandboxHelper.GetSandboxCacheFilePath();
string jsonData = FileUtility.ReadFile(filePath);
return JsonUtility.FromJson<PatchCache>(jsonData);
var patchCache = JsonUtility.FromJson<PatchCache>(jsonData);
YooLogger.Log($"Load cache file : {patchCache.CacheAppVersion}");
return patchCache;
}
else
{
YooLogger.Log($"Create patch cache to disk : {Application.version}");
YooLogger.Log($"Create cache file : {Application.version}");
PatchCache cache = new PatchCache();
cache.CacheAppVersion = Application.version;
string filePath = SandboxHelper.GetSandboxCacheFilePath();

View File

@@ -11,7 +11,7 @@ namespace YooAsset
/// </summary>
public InitializationOperation InitializeAsync()
{
var operation = new EditorModeInitializationOperation();
var operation = new EditorPlayModeInitializationOperation();
OperationSystem.ProcessOperaiton(operation);
return operation;
}
@@ -28,7 +28,7 @@ namespace YooAsset
BundleInfo IBundleServices.GetBundleInfo(string bundleName)
{
YooLogger.Warning($"Editor play mode can not get bundle info.");
BundleInfo bundleInfo = new BundleInfo(bundleName, bundleName);
BundleInfo bundleInfo = new BundleInfo(bundleName);
return bundleInfo;
}
string IBundleServices.GetBundleName(string assetPath)

View File

@@ -12,18 +12,15 @@ namespace YooAsset
// 参数相关
internal bool ClearCacheWhenDirty { private set; get; }
internal bool IgnoreResourceVersion { private set; get; }
private string _defaultHostServer;
private string _fallbackHostServer;
/// <summary>
/// 异步初始化
/// </summary>
public InitializationOperation InitializeAsync(bool clearCacheWhenDirty, bool ignoreResourceVersion,
string defaultHostServer, string fallbackHostServer)
public InitializationOperation InitializeAsync(bool clearCacheWhenDirty, string defaultHostServer, string fallbackHostServer)
{
ClearCacheWhenDirty = clearCacheWhenDirty;
IgnoreResourceVersion = ignoreResourceVersion;
_defaultHostServer = defaultHostServer;
_fallbackHostServer = fallbackHostServer;
@@ -32,6 +29,16 @@ namespace YooAsset
return operation;
}
/// <summary>
/// 异步更新资源版本号
/// </summary>
public UpdateStaticVersionOperation UpdateStaticVersionAsync(int timeout)
{
var operation = new HostPlayModeUpdateStaticVersionOperation(this, timeout);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
/// <summary>
/// 异步更新补丁清单
/// </summary>
@@ -166,19 +173,13 @@ namespace YooAsset
}
// WEB相关
public string GetPatchDownloadMainURL(int resourceVersion, string fileName)
public string GetPatchDownloadMainURL(string fileName)
{
if (IgnoreResourceVersion)
return $"{_defaultHostServer}/{fileName}";
else
return $"{_defaultHostServer}/{resourceVersion}/{fileName}";
return $"{_defaultHostServer}/{fileName}";
}
public string GetPatchDownloadFallbackURL(int resourceVersion, string fileName)
public string GetPatchDownloadFallbackURL(string fileName)
{
if (IgnoreResourceVersion)
return $"{_fallbackHostServer}/{fileName}";
else
return $"{_fallbackHostServer}/{resourceVersion}/{fileName}";
return $"{_fallbackHostServer}/{fileName}";
}
// 下载相关
@@ -195,10 +196,9 @@ namespace YooAsset
private BundleInfo ConvertToDownloadInfo(PatchBundle patchBundle)
{
// 注意:资源版本号只用于确定下载路径
string sandboxPath = SandboxHelper.MakeSandboxCacheFilePath(patchBundle.Hash);
string remoteMainURL = GetPatchDownloadMainURL(patchBundle.Version, patchBundle.Hash);
string remoteFallbackURL = GetPatchDownloadFallbackURL(patchBundle.Version, patchBundle.Hash);
BundleInfo bundleInfo = new BundleInfo(patchBundle, sandboxPath, remoteMainURL, remoteFallbackURL);
string remoteMainURL = GetPatchDownloadMainURL(patchBundle.Hash);
string remoteFallbackURL = GetPatchDownloadFallbackURL(patchBundle.Hash);
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromRemote, remoteMainURL, remoteFallbackURL);
return bundleInfo;
}
@@ -206,36 +206,34 @@ namespace YooAsset
BundleInfo IBundleServices.GetBundleInfo(string bundleName)
{
if (string.IsNullOrEmpty(bundleName))
return new BundleInfo(string.Empty, string.Empty);
return new BundleInfo(string.Empty);
if (LocalPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle patchBundle))
{
// 查询沙盒资源
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
{
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
return bundleInfo;
}
// 查询APP资源
if (AppPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
{
string appLoadPath = PathHelper.MakeStreamingLoadPath(appPatchBundle.Hash);
BundleInfo bundleInfo = new BundleInfo(appPatchBundle, appLoadPath);
BundleInfo bundleInfo = new BundleInfo(appPatchBundle, BundleInfo.ELoadMode.LoadFromStreaming);
return bundleInfo;
}
}
// 查询沙盒资源
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
{
string sandboxLoadPath = SandboxHelper.MakeSandboxCacheFilePath(patchBundle.Hash);
BundleInfo bundleInfo = new BundleInfo(patchBundle, sandboxLoadPath);
return bundleInfo;
}
// 从服务端下载
return ConvertToDownloadInfo(patchBundle);
}
else
{
YooLogger.Warning($"Not found bundle in patch manifest : {bundleName}");
BundleInfo bundleInfo = new BundleInfo(bundleName, string.Empty);
BundleInfo bundleInfo = new BundleInfo(bundleName);
return bundleInfo;
}
}

View File

@@ -42,18 +42,17 @@ namespace YooAsset
BundleInfo IBundleServices.GetBundleInfo(string bundleName)
{
if (string.IsNullOrEmpty(bundleName))
return new BundleInfo(string.Empty, string.Empty);
return new BundleInfo(string.Empty);
if (AppPatchManifest.Bundles.TryGetValue(bundleName, out PatchBundle patchBundle))
{
string localPath = PathHelper.MakeStreamingLoadPath(patchBundle.Hash);
BundleInfo bundleInfo = new BundleInfo(patchBundle, localPath);
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming);
return bundleInfo;
}
else
{
YooLogger.Warning($"Not found bundle in patch manifest : {bundleName}");
BundleInfo bundleInfo = new BundleInfo(bundleName, string.Empty);
BundleInfo bundleInfo = new BundleInfo(bundleName);
return bundleInfo;
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
/*
namespace YooAsset
{
internal class WebPlayModeImpl : IBundleServices
{
}
}
*/

View File

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

View File

@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("YooAsset.Editor")]
[assembly: InternalsVisibleTo("YooAsset.Editor")]
[assembly: InternalsVisibleTo("YooAsset.EditorExtend")]

View File

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

View File

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

namespace YooAsset
{
public class AddressLocationServices : ILocationServices
{
public string ConvertLocationToAssetPath(YooAssets.EPlayMode playMode, string location)
{
throw new System.NotImplementedException("该功能暂未支持!");
}
}
}

View File

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

View File

@@ -0,0 +1,105 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
public class DefaultLocationServices : ILocationServices
{
private readonly string _resourceRoot;
public DefaultLocationServices(string resourceRoot)
{
if (string.IsNullOrEmpty(resourceRoot) == false)
_resourceRoot = PathHelper.GetRegularPath(resourceRoot);
}
public string ConvertLocationToAssetPath(YooAssets.EPlayMode playMode, string location)
{
#if UNITY_EDITOR
CheckLocation(location);
#endif
if (playMode == YooAssets.EPlayMode.EditorPlayMode)
{
string filePath = CombineAssetPath(_resourceRoot, location);
return FindDatabaseAssetPath(filePath);
}
else
{
return CombineAssetPath(_resourceRoot, location);
}
}
/// <summary>
/// 合并资源路径
/// </summary>
private static string CombineAssetPath(string root, string location)
{
if (string.IsNullOrEmpty(root))
return location;
else
return $"{root}/{location}";
}
/// <summary>
/// 获取AssetDatabase的加载路径
/// </summary>
private static string FindDatabaseAssetPath(string filePath)
{
#if UNITY_EDITOR
if (File.Exists(filePath))
return filePath;
// AssetDatabase加载资源需要提供文件后缀格式然而资源定位地址并没有文件格式信息。
// 所以我们通过查找该文件所在文件夹内同名的首个文件来确定AssetDatabase的加载路径。
// 注意AssetDatabase.FindAssets() 返回文件内包括递归文件夹内所有资源的GUID
string fileName = Path.GetFileName(filePath);
string directory = PathHelper.GetDirectory(filePath);
string[] guids = UnityEditor.AssetDatabase.FindAssets(string.Empty, new[] { directory });
for (int i = 0; i < guids.Length; i++)
{
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]);
if (UnityEditor.AssetDatabase.IsValidFolder(assetPath))
continue;
string assetDirectory = PathHelper.GetDirectory(assetPath);
if (assetDirectory != directory)
continue;
string assetName = Path.GetFileNameWithoutExtension(assetPath);
if (assetName == fileName)
return assetPath;
}
// 没有找到同名的资源文件
YooLogger.Warning($"Not found asset : {filePath}");
return filePath;
#else
throw new System.NotImplementedException();
#endif
}
#if UNITY_EDITOR
private void CheckLocation(string location)
{
if (string.IsNullOrEmpty(location))
{
Debug.LogError("location param is null or empty!");
}
else
{
// 检查路径末尾是否有空格
int index = location.LastIndexOf(" ");
if (index != -1)
{
if (location.Length == index + 1)
Debug.LogWarning($"Found blank character in location : \"{location}\"");
}
if (location.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
Debug.LogWarning($"Found illegal character in location : \"{location}\"");
}
}
#endif
}
}

View File

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

View File

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

namespace YooAsset
{
public interface ILocationServices
{
/// <summary>
/// 定位地址转换为资源路径
/// </summary>
string ConvertLocationToAssetPath(YooAssets.EPlayMode playMode, string location);
}
}

View File

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

View File

@@ -18,12 +18,7 @@ namespace YooAsset
/// <summary>
/// 构建输出的补丁清单文件名称
/// </summary>
public string PatchManifestFileName = "PatchManifest.bytes";
/// <summary>
/// 构建输出的补丁清单哈希文件名称
/// </summary>
public string PatchManifestHashFileName = "PatchManifestHash.bytes";
public string PatchManifestFileName = "PatchManifest";
/// <summary>
/// 构建输出的Unity清单文件名称
@@ -34,5 +29,10 @@ namespace YooAsset
/// 构建输出的报告文件
/// </summary>
public const string ReportFileName = "BuildReport.json";
/// <summary>
/// 静态版本文件
/// </summary>
public const string VersionFileName = "StaticVersion.bytes";
}
}

View File

@@ -31,5 +31,21 @@ namespace YooAsset
YooLogger.Log("YooAsset use custom settings.");
}
}
/// <summary>
/// 获取补丁清单文件完整名称
/// </summary>
public static string GetPatchManifestFileName(int resourceVersion)
{
return $"{Setting.PatchManifestFileName}_{resourceVersion}.bytes";
}
/// <summary>
/// 获取补丁清单哈希文件完整名称
/// </summary>
public static string GetPatchManifestHashFileName(int resourceVersion)
{
return $"{Setting.PatchManifestFileName}_{resourceVersion}.hash";
}
}
}

View File

@@ -30,7 +30,7 @@ namespace YooAsset
/// </summary>
public static string MakeStreamingLoadPath(string path)
{
return StringUtility.Format("{0}/{1}", UnityEngine.Application.streamingAssetsPath, path);
return StringUtility.Format("{0}/YooAssets/{1}", UnityEngine.Application.streamingAssetsPath, path);
}
/// <summary>
@@ -61,7 +61,6 @@ namespace YooAsset
/// </summary>
public static string ConvertToWWWPath(string path)
{
// 注意WWW加载方式必须要在路径前面加file://
#if UNITY_EDITOR
return StringUtility.Format("file:///{0}", path);
#elif UNITY_IPHONE
@@ -70,56 +69,8 @@ namespace YooAsset
return path;
#elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path);
#endif
}
/// <summary>
/// 合并资源路径
/// </summary>
public static string CombineAssetPath(string root, string location)
{
if (string.IsNullOrEmpty(root))
return location;
else
return $"{root}/{location}";
}
/// <summary>
/// 获取AssetDatabase的加载路径
/// </summary>
public static string FindDatabaseAssetPath(string filePath)
{
#if UNITY_EDITOR
if (File.Exists(filePath))
return filePath;
// AssetDatabase加载资源需要提供文件后缀格式然而资源定位地址并没有文件格式信息。
// 所以我们通过查找该文件所在文件夹内同名的首个文件来确定AssetDatabase的加载路径。
// 注意AssetDatabase.FindAssets() 返回文件内包括递归文件夹内所有资源的GUID
string fileName = Path.GetFileName(filePath);
string directory = GetDirectory(filePath);
string[] guids = UnityEditor.AssetDatabase.FindAssets(string.Empty, new[] { directory });
for (int i = 0; i < guids.Length; i++)
{
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]);
if (UnityEditor.AssetDatabase.IsValidFolder(assetPath))
continue;
string assetDirectory = GetDirectory(assetPath);
if (assetDirectory != directory)
continue;
string assetName = Path.GetFileNameWithoutExtension(assetPath);
if (assetName == fileName)
return assetPath;
}
// 没有找到同名的资源文件
YooLogger.Warning($"Not found asset : {filePath}");
return filePath;
#else
throw new System.NotImplementedException();
#elif UNITY_WEBGL
return path;
#endif
}
}
@@ -142,16 +93,6 @@ namespace YooAsset
Directory.Delete(directoryPath, true);
}
/// <summary>
/// 删除沙盒内补丁清单文件
/// </summary>
public static void DeleteSandboxPatchManifestFile()
{
string filePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
if (File.Exists(filePath))
File.Delete(filePath);
}
/// <summary>
/// 删除沙盒内的缓存文件
/// </summary>
@@ -190,29 +131,6 @@ namespace YooAsset
return File.Exists(filePath);
}
/// <summary>
/// 检测沙盒内补丁清单文件是否存在
/// </summary>
public static bool CheckSandboxPatchManifestFileExist()
{
string filePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
return File.Exists(filePath);
}
/// <summary>
/// 获取沙盒内补丁清单文件的哈希值
/// 注意:如果沙盒内补丁清单文件不存在,返回空字符串
/// </summary>
/// <returns></returns>
public static string GetSandboxPatchManifestFileHash()
{
string filePath = PathHelper.MakePersistentLoadPath(YooAssetSettingsData.Setting.PatchManifestFileName);
if (File.Exists(filePath))
return HashUtility.FileMD5(filePath);
else
return string.Empty;
}
/// <summary>
/// 获取缓存文件的存储路径
/// </summary>
@@ -232,6 +150,7 @@ namespace YooAsset
/// </summary>
public static List<BundleInfo> GetUnpackListByTags(PatchManifest appPatchManifest, string[] tags)
{
// 注意:离线运行模式也依赖下面逻辑,所以判断沙盒内文件是否存在不能通过缓存系统去验证。
List<PatchBundle> downloadList = new List<PatchBundle>(1000);
foreach (var patchBundle in appPatchManifest.BundleList)
{
@@ -244,19 +163,11 @@ namespace YooAsset
if (patchBundle.IsBuildin == false)
continue;
// 如果是纯内置资源
if (patchBundle.IsPureBuildin())
// 查询DLC资源
if (patchBundle.HasTag(tags))
{
downloadList.Add(patchBundle);
}
else
{
// 查询DLC资源
if (patchBundle.HasTag(tags))
{
downloadList.Add(patchBundle);
}
}
}
return ConvertToUnpackList(downloadList);
@@ -273,9 +184,10 @@ namespace YooAsset
}
private static BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle)
{
string sandboxPath = SandboxHelper.MakeSandboxCacheFilePath(patchBundle.Hash);
string streamingLoadPath = PathHelper.MakeStreamingLoadPath(patchBundle.Hash);
BundleInfo bundleInfo = new BundleInfo(patchBundle, sandboxPath, streamingLoadPath, streamingLoadPath);
// 注意:我们把流加载路径指定为远端下载地址
string streamingPath = PathHelper.MakeStreamingLoadPath(patchBundle.Hash);
streamingPath = PathHelper.ConvertToWWWPath(streamingPath);
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromRemote, streamingPath, streamingPath);
return bundleInfo;
}
}

View File

@@ -10,7 +10,7 @@ namespace YooAsset
/// <summary>
/// 运行模式
/// </summary>
private enum EPlayMode
public enum EPlayMode
{
/// <summary>
/// 编辑器下模拟运行模式
@@ -28,16 +28,18 @@ namespace YooAsset
HostPlayMode,
}
/// <summary>
/// 初始化参数
/// </summary>
public abstract class CreateParameters
{
/// <summary>
/// 资源定位的根路径
/// 例如Assets/MyResource
/// 资源定位服务接口
/// </summary>
public string LocationRoot;
public ILocationServices LocationServices = null;
/// <summary>
/// 文件解密接口
/// 文件解密服务接口
/// </summary>
public IDecryptionServices DecryptionServices = null;
@@ -82,11 +84,6 @@ namespace YooAsset
/// </summary>
public bool ClearCacheWhenDirty;
/// <summary>
/// 忽略资源版本号
/// </summary>
public bool IgnoreResourceVersion;
/// <summary>
/// 默认的资源服务器下载地址
/// </summary>
@@ -105,9 +102,9 @@ namespace YooAsset
private static bool _isInitialize = false;
private static string _locationRoot;
private static EPlayMode _playMode;
private static IBundleServices _bundleServices;
private static ILocationServices _locationServices;
private static EditorPlayModeImpl _editorPlayModeImpl;
private static OfflinePlayModeImpl _offlinePlayModeImpl;
private static HostPlayModeImpl _hostPlayModeImpl;
@@ -124,6 +121,11 @@ namespace YooAsset
if (parameters == null)
throw new Exception($"YooAsset create parameters is null.");
if (parameters.LocationServices == null)
throw new Exception($"{nameof(IBundleServices)} is null.");
else
_locationServices = parameters.LocationServices;
#if !UNITY_EDITOR
if (parameters is EditorPlayModeParameters)
throw new Exception($"Editor play mode only support unity editor.");
@@ -154,9 +156,6 @@ namespace YooAsset
YooLogger.Warning($"{nameof(parameters.OperationSystemMaxTimeSlice)} minimum value is 33 milliseconds");
}
if (string.IsNullOrEmpty(parameters.LocationRoot) == false)
_locationRoot = PathHelper.GetRegularPath(parameters.LocationRoot);
if (parameters.AutoReleaseInterval > 0)
_releaseCD = parameters.AutoReleaseInterval;
@@ -176,8 +175,12 @@ namespace YooAsset
// 初始化下载系统
if (_playMode == EPlayMode.HostPlayMode)
{
#if UNITY_WEBGL
throw new Exception($"{EPlayMode.HostPlayMode} not supports WebGL platform !");
#else
var hostPlayModeParameters = parameters as HostPlayModeParameters;
DownloadSystem.Initialize(hostPlayModeParameters.BreakpointResumeFileSize);
#endif
}
// 初始化资源系统
@@ -203,7 +206,6 @@ namespace YooAsset
var hostPlayModeParameters = parameters as HostPlayModeParameters;
return _hostPlayModeImpl.InitializeAsync(
hostPlayModeParameters.ClearCacheWhenDirty,
hostPlayModeParameters.IgnoreResourceVersion,
hostPlayModeParameters.DefaultHostServer,
hostPlayModeParameters.FallbackHostServer);
}
@@ -213,6 +215,36 @@ namespace YooAsset
}
}
/// <summary>
/// 向网络端请求静态资源版本号
/// </summary>
/// <param name="timeout">超时时间默认值60秒</param>
public static UpdateStaticVersionOperation UpdateStaticVersionAsync(int timeout = 60)
{
if (_playMode == EPlayMode.EditorPlayMode)
{
var operation = new EditorPlayModeUpdateStaticVersionOperation();
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
var operation = new OfflinePlayModeUpdateStaticVersionOperation();
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
{
if (_hostPlayModeImpl == null)
throw new Exception("YooAsset is not initialized.");
return _hostPlayModeImpl.UpdateStaticVersionAsync(timeout);
}
else
{
throw new NotImplementedException();
}
}
/// <summary>
/// 向网络端请求并更新补丁清单
/// </summary>
@@ -222,7 +254,7 @@ namespace YooAsset
{
if (_playMode == EPlayMode.EditorPlayMode)
{
var operation = new EditorModeUpdateManifestOperation();
var operation = new EditorPlayModeUpdateManifestOperation();
OperationSystem.ProcessOperaiton(operation);
return operation;
}
@@ -278,7 +310,7 @@ namespace YooAsset
/// </summary>
public static BundleInfo GetBundleInfo(string location)
{
string assetPath = ConvertLocationToAssetPath(location);
string assetPath = _locationServices.ConvertLocationToAssetPath(_playMode, location);
string bundleName = _bundleServices.GetBundleName(assetPath);
return _bundleServices.GetBundleInfo(bundleName);
}
@@ -321,7 +353,7 @@ namespace YooAsset
/// <param name="priority">优先级</param>
public static SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100)
{
string scenePath = ConvertLocationToAssetPath(location);
string scenePath = _locationServices.ConvertLocationToAssetPath(_playMode, location);
var handle = AssetSystem.LoadSceneAsync(scenePath, sceneMode, activateOnLoad, priority);
return handle;
}
@@ -331,10 +363,40 @@ namespace YooAsset
/// <summary>
/// 异步加载原生文件
/// </summary>
public static RawFileOperation LoadRawFileAsync(string location, string savePath)
/// <param name="location">资源的定位地址</param>
/// <param name="copyPath">拷贝路径</param>
public static RawFileOperation LoadRawFileAsync(string location, string copyPath = null)
{
string assetPath = ConvertLocationToAssetPath(location);
return AssetSystem.LoadRawFileAsync(assetPath, savePath);
string assetPath = _locationServices.ConvertLocationToAssetPath(_playMode, location);
if (_playMode == EPlayMode.EditorPlayMode)
{
BundleInfo bundleInfo = new BundleInfo(assetPath);
RawFileOperation operation = new EditorPlayModeRawFileOperation(bundleInfo, copyPath);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
IBundleServices bundleServices = _offlinePlayModeImpl;
string bundleName = bundleServices.GetBundleName(assetPath);
BundleInfo bundleInfo = bundleServices.GetBundleInfo(bundleName);
RawFileOperation operation = new OfflinePlayModeRawFileOperation(bundleInfo, copyPath);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
{
IBundleServices bundleServices = _hostPlayModeImpl;
string bundleName = bundleServices.GetBundleName(assetPath);
BundleInfo bundleInfo = bundleServices.GetBundleInfo(bundleName);
RawFileOperation operation = new HostPlayModeRawFileOperation(bundleInfo, copyPath);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else
{
throw new NotImplementedException();
}
}
@@ -342,7 +404,7 @@ namespace YooAsset
/// 同步加载资源对象
/// </summary>
/// <typeparam name="TObject">资源类型</typeparam>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
public static AssetOperationHandle LoadAssetSync<TObject>(string location) where TObject : class
{
return LoadAssetInternal(location, typeof(TObject), true);
@@ -351,7 +413,7 @@ namespace YooAsset
/// <summary>
/// 同步加载资源对象
/// </summary>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
/// <param name="type">资源类型</param>
public static AssetOperationHandle LoadAssetSync(string location, System.Type type)
{
@@ -362,7 +424,7 @@ namespace YooAsset
/// 同步加载子资源对象
/// </summary>
/// <typeparam name="TObject">资源类型</typeparam>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
public static SubAssetsOperationHandle LoadSubAssetsSync<TObject>(string location)
{
return LoadSubAssetsInternal(location, typeof(TObject), true);
@@ -371,7 +433,7 @@ namespace YooAsset
/// <summary>
/// 同步加载子资源对象
/// </summary>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
/// <param name="type">子对象类型</param>
public static SubAssetsOperationHandle LoadSubAssetsSync(string location, System.Type type)
{
@@ -383,7 +445,7 @@ namespace YooAsset
/// 异步加载资源对象
/// </summary>
/// <typeparam name="TObject">资源类型</typeparam>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
public static AssetOperationHandle LoadAssetAsync<TObject>(string location)
{
return LoadAssetInternal(location, typeof(TObject), false);
@@ -392,7 +454,7 @@ namespace YooAsset
/// <summary>
/// 异步加载资源对象
/// </summary>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
/// <param name="type">资源类型</param>
public static AssetOperationHandle LoadAssetAsync(string location, System.Type type)
{
@@ -403,7 +465,7 @@ namespace YooAsset
/// 异步加载子资源对象
/// </summary>
/// <typeparam name="TObject">资源类型</typeparam>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
public static SubAssetsOperationHandle LoadSubAssetsAsync<TObject>(string location)
{
return LoadSubAssetsInternal(location, typeof(TObject), false);
@@ -412,7 +474,7 @@ namespace YooAsset
/// <summary>
/// 异步加载子资源对象
/// </summary>
/// <param name="location">资源对象相对路径</param>
/// <param name="location">资源的定位地址</param>
/// <param name="type">子对象类型</param>
public static SubAssetsOperationHandle LoadSubAssetsAsync(string location, System.Type type)
{
@@ -422,7 +484,7 @@ namespace YooAsset
private static AssetOperationHandle LoadAssetInternal(string location, System.Type assetType, bool waitForAsyncComplete)
{
string assetPath = ConvertLocationToAssetPath(location);
string assetPath = _locationServices.ConvertLocationToAssetPath(_playMode, location);
var handle = AssetSystem.LoadAssetAsync(assetPath, assetType);
if (waitForAsyncComplete)
handle.WaitForAsyncComplete();
@@ -430,7 +492,7 @@ namespace YooAsset
}
private static SubAssetsOperationHandle LoadSubAssetsInternal(string location, System.Type assetType, bool waitForAsyncComplete)
{
string assetPath = ConvertLocationToAssetPath(location);
string assetPath = _locationServices.ConvertLocationToAssetPath(_playMode, location);
var handle = AssetSystem.LoadSubAssetsAsync(assetPath, assetType);
if (waitForAsyncComplete)
handle.WaitForAsyncComplete();
@@ -510,7 +572,7 @@ namespace YooAsset
List<string> assetPaths = new List<string>(locations.Length);
foreach (var location in locations)
{
string assetPath = ConvertLocationToAssetPath(location);
string assetPath = _locationServices.ConvertLocationToAssetPath(_playMode, location);
assetPaths.Add(assetPath);
}
return _hostPlayModeImpl.CreateDownloaderByPaths(assetPaths, downloadingMaxNumber, failedTryAgain);
@@ -613,22 +675,6 @@ namespace YooAsset
}
}
}
/// <summary>
/// 定位地址转换为资源路径
/// </summary>
private static string ConvertLocationToAssetPath(string location)
{
if (_playMode == EPlayMode.EditorPlayMode)
{
string filePath = PathHelper.CombineAssetPath(_locationRoot, location);
return PathHelper.FindDatabaseAssetPath(filePath);
}
else
{
return PathHelper.CombineAssetPath(_locationRoot, location);
}
}
#endregion
}
}

View File

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

View File

@@ -4,23 +4,19 @@
如果是本地测试可以在本地创建一个WEB服务器然后将补丁包拷贝到WEB服务器下。
**按照补丁版本目录部署**
````
CDN
└─android
├─100
├─101
└─102
````
**按照游戏版本目录部署**
在业务开发过程中每个游戏版本实际都会创建一个SVN分支该分支工程内每次构建的补丁包上传到对应的CDN目录下即可。
````
CDN
└─android
├─v1.0
├─v1.1
└─v2.0
└─iphone
├─v1.0
├─v1.1
└─v2.0
````

View File

@@ -17,7 +17,7 @@ YooAssets.InitializeAsync(CreateParameters parameters);
private IEnumerator InitializeYooAsset()
{
var createParameters = new YooAssets.EditorPlayModeParameters();
createParameters.LocationRoot = "Assets/GameRes";
createParameters.LocationServices = new DefaultLocationServices("Assets/GameRes");
yield return YooAssets.InitializeAsync(createParameters);
}
````
@@ -32,7 +32,7 @@ private IEnumerator InitializeYooAsset()
private IEnumerator InitializeYooAsset()
{
var createParameters = new YooAssets.OfflinePlayModeParameters();
createParameters.LocationRoot = "Assets/GameRes";
createParameters.LocationServices = new DefaultLocationServices("Assets/GameRes");
yield return YooAssets.InitializeAsync(createParameters);
}
````
@@ -43,10 +43,12 @@ private IEnumerator InitializeYooAsset()
注意:该模式需要构建资源包
- LocationRoot : 资源定位的根路径,所有通过代码加载的资源文件都需要放在资源定位的根路径下
- LocationServices : 资源定位的实例类
1. 默认的资源定位服务类DefaultLocationServices
2. 可寻址的资源定位服务类AdressLocationServices
3. 开发者自定义的资源定位服务类需要提供实现ILocationServices接口的实例类。
- DecryptionServices : 如果资源包在构建的时候有加密需要提供实现IDecryptionServices接口的实例类。
- ClearCacheWhenDirty : 安装包在覆盖安装的时候,是否清空沙盒缓存文件夹。
- IgnoreResourceVersion : 是否忽略资源版本号,请参考进阶教程。
- DefaultHostServer : 默认的资源服务器IP地址。
- FallbackHostServer : 备用的资源服务器IP地址。
@@ -54,10 +56,9 @@ private IEnumerator InitializeYooAsset()
private IEnumerator InitializeYooAsset()
{
var createParameters = new YooAssets.HostPlayModeParameters();
createParameters.LocationRoot = "Assets/GameRes";
createParameters.LocationServices = new DefaultLocationServices("Assets/GameRes");
createParameters.DecryptionServices = null;
createParameters.ClearCacheWhenDirty = false;
createParameters.IgnoreResourceVersion = false;
createParameters.DefaultHostServer = "http://127.0.0.1/CDN1/Android";
createParameters.FallbackHostServer = "http://127.0.0.1/CDN2/Android";
yield return YooAssets.InitializeAsync(createParameters);

View File

@@ -1,18 +1,39 @@
# 资源更新
**获取资源版本**
对于联机运行模式,在更新补丁清单之前,需要获取一个资源版本号。
该资源版本号可以通过YooAssets提供的接口来更新也可以通过HTTP访问游戏服务器来获取。
````c#
private IEnumerator UpdateStaticVersion()
{
UpdateStaticVersionOperation operation = YooAssets.UpdateStaticVersionAsync();
yield return operation;
if (operation.Status == EOperationStatus.Succeed)
{
//更新成功
int resourceVersion = operation.ResourceVersion;
Debug.Log($"Update resource Version : {resourceVersion}");
}
else
{
//更新失败
Debug.LogError(operation.Error);
}
}
````
**更新补丁清单**
对于联机运行模式,在初始化资源系统之后,需要立刻更新资源清单。
**注意**:在初始化资源系统的时候,可以选择是否忽略资源版本号,这会影响到我们的更新步骤。
- 没有忽略资源版本号在更新之前先获取更新的资源版本号一般通过HTTP访问游戏服务器来获取。
- 忽略资源版本号在更新的时候资源版本号可以设置为0。
对于联机运行模式,在获取到资源版本号之后,就可以更新资源清单
````c#
private IEnumerator UpdatePatchManifest()
{
UpdateManifestOperation operation = YooAssets.UpdateManifestAsync(updateResourceVersion);
UpdateManifestOperation operation = YooAssets.UpdateManifestAsync(resourceVersion);
yield return operation;
if (operation.Status == EOperationStatus.Succeed)

View File

@@ -1,7 +1,5 @@
# 资源加载
在加载资源对象的时候只需要提供相对路径统一约定该相对路径名称为location
加载接口:
- YooAssets.LoadAssetSync() 同步加载资源对象接口
@@ -11,6 +9,8 @@
- YooAssets.LoadSceneAsync() 异步加载场景接口
- YooAssets.LoadRawFileAsync() 异步读取原生文件接口
统一约定location为资源的定位地址也是加载资源对象的唯一标识符。
**加载路径的匹配方式**
````C#
@@ -121,3 +121,32 @@ IEnumerator Start()
}
````
**FairyGUI加载方案**
注意在FairyGUI的面板销毁的时候将资源句柄列表释放否则会造成资源泄漏。
````c#
// 资源句柄列表
private List<AssetOperationHandle> _handles = new List<AssetOperationHandle>(100);
// 加载方法
private object LoadFunc(string name, string extension, System.Type type, out DestroyMethod method)
{
method = DestroyMethod.None;
string location = $"FairyRes/{name}{extension}";
var handle = YooAssets.LoadAssetSync(location , type);
_handles.Add(handle);
return handle.AssetObject;
}
// 释放资源句柄列表
private void ReleaseHandles()
{
foreach(var handle in _handles)
{
handle.Release();
}
_handles.Clear();
}
````

12
Docs/Contributor.md Normal file
View File

@@ -0,0 +1,12 @@
# 感谢所有支持YooAsset的小伙伴们
**特别感谢以下QQ社区的小伙伴**
他们帮忙协助解决了很多BUG以及提出了很多宝贵的意见
- 黄色幻想
- 新乞丐王子

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 27 KiB

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