diff --git a/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleFileLoader.cs b/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleFileLoader.cs index f79cf43..9e305c5 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleFileLoader.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleFileLoader.cs @@ -13,6 +13,8 @@ namespace YooAsset None = 0, Download, CheckDownload, + Unpack, + CheckUnpack, LoadFile, CheckLoadFile, Done, @@ -22,8 +24,10 @@ namespace YooAsset private string _fileLoadPath; private bool _isWaitForAsyncComplete = false; private bool _isShowWaitForAsyncError = false; + private DownloaderBase _unpacker; private DownloaderBase _downloader; private AssetBundleCreateRequest _createRequest; + private FileStream _fileStream; public AssetBundleFileLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo) @@ -47,8 +51,22 @@ namespace YooAsset } else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming) { +#if UNITY_ANDROID + EBundleLoadMethod loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod; + if (loadMethod == EBundleLoadMethod.LoadFromMemory || loadMethod == EBundleLoadMethod.LoadFromStream) + { + _steps = ESteps.Unpack; + _fileLoadPath = MainBundleInfo.Bundle.CachedFilePath; + } + else + { + _steps = ESteps.LoadFile; + _fileLoadPath = MainBundleInfo.Bundle.StreamingFilePath; + } +#else _steps = ESteps.LoadFile; _fileLoadPath = MainBundleInfo.Bundle.StreamingFilePath; +#endif } else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache) { @@ -87,7 +105,34 @@ namespace YooAsset } } - // 3. 加载AssetBundle + // 3. 内置文件解压 + if (_steps == ESteps.Unpack) + { + int failedTryAgain = 1; + var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(MainBundleInfo.Bundle); + _unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); + _steps = ESteps.CheckUnpack; + } + + // 4.检测内置文件解压结果 + if (_steps == ESteps.CheckUnpack) + { + if (_unpacker.IsDone() == false) + return; + + if (_unpacker.HasError()) + { + _steps = ESteps.Done; + Status = EStatus.Failed; + LastError = _unpacker.GetLastError(); + } + else + { + _steps = ESteps.LoadFile; + } + } + + // 5. 加载AssetBundle if (_steps == ESteps.LoadFile) { #if UNITY_EDITOR @@ -103,31 +148,63 @@ namespace YooAsset #endif // Load assetBundle file - if (MainBundleInfo.Bundle.IsEncrypted) - { - if (Impl.DecryptionServices == null) - throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.Bundle.BundleName}"); - - DecryptionFileInfo fileInfo = new DecryptionFileInfo(); - fileInfo.BundleName = MainBundleInfo.Bundle.BundleName; - fileInfo.FileHash = MainBundleInfo.Bundle.FileHash; - ulong offset = Impl.DecryptionServices.GetFileOffset(fileInfo); - if (_isWaitForAsyncComplete) - CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath, 0, offset); - else - _createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset); - } - else + var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod; + if (loadMethod == EBundleLoadMethod.Normal) { if (_isWaitForAsyncComplete) CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath); else _createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath); } + else + { + if (Impl.DecryptionServices == null) + { + _steps = ESteps.Done; + Status = EStatus.Failed; + LastError = $"{nameof(IDecryptionServices)} is null : {MainBundleInfo.Bundle.BundleName}"; + YooLogger.Error(LastError); + return; + } + + DecryptFileInfo fileInfo = new DecryptFileInfo(); + fileInfo.BundleName = MainBundleInfo.Bundle.BundleName; + fileInfo.FilePath = _fileLoadPath; + + if (loadMethod == EBundleLoadMethod.LoadFromFileOffset) + { + ulong offset = Impl.DecryptionServices.LoadFromFileOffset(fileInfo); + if (_isWaitForAsyncComplete) + CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath, 0, offset); + else + _createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset); + } + else if (loadMethod == EBundleLoadMethod.LoadFromMemory) + { + byte[] fileData = Impl.DecryptionServices.LoadFromMemory(fileInfo); + if (_isWaitForAsyncComplete) + CacheBundle = AssetBundle.LoadFromMemory(fileData); + else + _createRequest = AssetBundle.LoadFromMemoryAsync(fileData); + } + else if (loadMethod == EBundleLoadMethod.LoadFromStream) + { + _fileStream = Impl.DecryptionServices.LoadFromStream(fileInfo); + uint managedReadBufferSize = Impl.DecryptionServices.GetManagedReadBufferSize(); + if (_isWaitForAsyncComplete) + CacheBundle = AssetBundle.LoadFromStream(_fileStream, 0, managedReadBufferSize); + else + _createRequest = AssetBundle.LoadFromStreamAsync(_fileStream, 0, managedReadBufferSize); + } + else + { + throw new System.NotImplementedException(); + } + } _steps = ESteps.CheckLoadFile; } - // 4. 检测AssetBundle加载结果 + // 6. 检测AssetBundle加载结果 if (_steps == ESteps.CheckLoadFile) { if (_createRequest != null) @@ -177,6 +254,21 @@ namespace YooAsset } } + /// + /// 销毁 + /// + public override void Destroy(bool forceDestroy) + { + base.Destroy(forceDestroy); + + if (_fileStream != null) + { + _fileStream.Close(); + _fileStream.Dispose(); + _fileStream = null; + } + } + /// /// 主线程等待异步操作完毕 /// diff --git a/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleLoaderBase.cs b/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleLoaderBase.cs index 125f836..ff345ea 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleLoaderBase.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleLoaderBase.cs @@ -89,7 +89,7 @@ namespace YooAsset /// /// 销毁 /// - public void Destroy(bool forceDestroy) + public virtual void Destroy(bool forceDestroy) { IsDestroyed = true; diff --git a/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleWebLoader.cs b/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleWebLoader.cs index d9f7110..a626247 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleWebLoader.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/Loader/AssetBundleWebLoader.cs @@ -17,7 +17,7 @@ namespace YooAsset LoadCacheFile, CheckLoadCacheFile, LoadWebFile, - CheckLoadWebFile, + CheckLoadWebFile, TryLoadWebFile, Done, } @@ -30,7 +30,7 @@ namespace YooAsset private UnityWebRequest _webRequest; private AssetBundleCreateRequest _createRequest; - + public AssetBundleWebLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo) { } @@ -108,20 +108,18 @@ namespace YooAsset #endif // Load assetBundle file - if (MainBundleInfo.Bundle.IsEncrypted) + var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod; + if (loadMethod == EBundleLoadMethod.Normal) { - if (Impl.DecryptionServices == null) - throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.Bundle.BundleName}"); - - DecryptionFileInfo fileInfo = new DecryptionFileInfo(); - fileInfo.BundleName = MainBundleInfo.Bundle.BundleName; - fileInfo.FileHash = MainBundleInfo.Bundle.FileHash; - ulong offset = Impl.DecryptionServices.GetFileOffset(fileInfo); - _createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset); + _createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath); } else { - _createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath); + _steps = ESteps.Done; + Status = EStatus.Failed; + LastError = $"WebGL not support encrypted bundle file : {MainBundleInfo.Bundle.BundleName}"; + YooLogger.Error(LastError); + return; } _steps = ESteps.CheckLoadCacheFile; } diff --git a/Assets/YooAsset/Runtime/AssetSystem/Loader/EBundleLoadMethod.cs b/Assets/YooAsset/Runtime/AssetSystem/Loader/EBundleLoadMethod.cs new file mode 100644 index 0000000..625fcce --- /dev/null +++ b/Assets/YooAsset/Runtime/AssetSystem/Loader/EBundleLoadMethod.cs @@ -0,0 +1,29 @@ + +namespace YooAsset +{ + /// + /// Bundle文件的加载方法 + /// + public enum EBundleLoadMethod + { + /// + /// 正常加载(不需要解密) + /// + Normal = 0, + + /// + /// 通过文件偏移来解密加载 + /// + LoadFromFileOffset = 1, + + /// + /// 通过文件内存来解密加载 + /// + LoadFromMemory = 2, + + /// + /// 通过文件流来解密加载 + /// + LoadFromStream = 3, + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/AssetSystem/Loader/EBundleLoadMethod.cs.meta b/Assets/YooAsset/Runtime/AssetSystem/Loader/EBundleLoadMethod.cs.meta new file mode 100644 index 0000000..10eb8db --- /dev/null +++ b/Assets/YooAsset/Runtime/AssetSystem/Loader/EBundleLoadMethod.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e32c14ed62806b4189d20ad48ce7631 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs b/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs index 736aac9..fb42394 100644 --- a/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs +++ b/Assets/YooAsset/Runtime/AssetSystem/Operations/RawFileOperation.cs @@ -171,14 +171,14 @@ namespace YooAsset { None, Prepare, - DownloadBuildinFile, - CheckDownload, + Unpack, + CheckUnpack, CheckAndCopyFile, Done, } private ESteps _steps = ESteps.None; - private DownloaderBase _downloader; + private DownloaderBase _unpacker; public OfflinePlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath) { @@ -203,7 +203,7 @@ namespace YooAsset } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming) { - _steps = ESteps.DownloadBuildinFile; + _steps = ESteps.Unpack; } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache) { @@ -215,27 +215,27 @@ namespace YooAsset } } - // 2. 下载文件 - if (_steps == ESteps.DownloadBuildinFile) + // 2. 内置文件解压 + if (_steps == ESteps.Unpack) { - int failedTryAgain = int.MaxValue; + int failedTryAgain = 1; var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(_bundleInfo.Bundle); - _downloader = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); - _steps = ESteps.CheckDownload; + _unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); + _steps = ESteps.CheckUnpack; } - // 3. 检测下载结果 - if (_steps == ESteps.CheckDownload) + // 3. 检测内置文件解压结果 + if (_steps == ESteps.CheckUnpack) { - Progress = _downloader.DownloadProgress; - if (_downloader.IsDone() == false) + Progress = _unpacker.DownloadProgress; + if (_unpacker.IsDone() == false) return; - if (_downloader.HasError()) + if (_unpacker.HasError()) { _steps = ESteps.Done; Status = EOperationStatus.Failed; - Error = _downloader.GetLastError(); + Error = _unpacker.GetLastError(); } else { @@ -306,14 +306,16 @@ namespace YooAsset { None, Prepare, - DownloadWebFile, - DownloadBuildinFile, + Download, CheckDownload, + Unpack, + CheckUnpack, CheckAndCopyFile, Done, } private ESteps _steps = ESteps.None; + private DownloaderBase _unpacker; private DownloaderBase _downloader; internal HostPlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath) @@ -339,11 +341,11 @@ namespace YooAsset } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote) { - _steps = ESteps.DownloadWebFile; + _steps = ESteps.Download; } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming) { - _steps = ESteps.DownloadBuildinFile; + _steps = ESteps.Unpack; } else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache) { @@ -356,23 +358,14 @@ namespace YooAsset } // 2. 下载远端文件 - if (_steps == ESteps.DownloadWebFile) + if (_steps == ESteps.Download) { int failedTryAgain = int.MaxValue; _downloader = DownloadSystem.BeginDownload(_bundleInfo, failedTryAgain); _steps = ESteps.CheckDownload; } - // 3. 下载内置文件 - if (_steps == ESteps.DownloadBuildinFile) - { - int failedTryAgain = int.MaxValue; - var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(_bundleInfo.Bundle); - _downloader = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); - _steps = ESteps.CheckDownload; - } - - // 4. 检测下载结果 + // 3. 检测下载结果 if (_steps == ESteps.CheckDownload) { Progress = _downloader.DownloadProgress; @@ -391,6 +384,34 @@ namespace YooAsset } } + // 3. 解压内置文件 + if (_steps == ESteps.Unpack) + { + int failedTryAgain = 1; + var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(_bundleInfo.Bundle); + _unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); + _steps = ESteps.CheckUnpack; + } + + // 4. 检测解压结果 + if (_steps == ESteps.CheckUnpack) + { + Progress = _unpacker.DownloadProgress; + if (_unpacker.IsDone() == false) + return; + + if (_unpacker.HasError()) + { + _steps = ESteps.Done; + Status = EOperationStatus.Failed; + Error = _unpacker.GetLastError(); + } + else + { + _steps = ESteps.CheckAndCopyFile; + } + } + // 5. 检测并拷贝原生文件 if (_steps == ESteps.CheckAndCopyFile) { diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs b/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs index d2b5721..7db22c7 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchBundle.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using System.IO; namespace YooAsset { @@ -27,27 +26,21 @@ namespace YooAsset /// public long FileSize; + /// + /// 是否为原生文件 + /// + public bool IsRawFile; + + /// + /// 加载方法 + /// + public byte LoadMethod; + /// /// 资源包的分类标签 /// public string[] Tags; - /// - /// Flags - /// - public int Flags; - - - /// - /// 是否为原生文件 - /// - public bool IsRawFile { private set; get; } - - /// - /// 是否为加密文件 - /// - public bool IsEncrypted { private set; get; } - /// /// 文件名称 /// @@ -87,37 +80,15 @@ namespace YooAsset } - public PatchBundle(string bundleName, string fileHash, string fileCRC, long fileSize, string[] tags) + public PatchBundle(string bundleName, string fileHash, string fileCRC, long fileSize, bool isRawFile, byte loadMethod, string[] tags) { BundleName = bundleName; FileHash = fileHash; FileCRC = fileCRC; FileSize = fileSize; - Tags = tags; - } - - /// - /// 设置Flags - /// - public void SetFlagsValue(bool isRawFile, bool isEncrypted) - { IsRawFile = isRawFile; - IsEncrypted = isEncrypted; - - BitMask32 mask = new BitMask32(0); - if (isRawFile) mask.Open(0); - if (isEncrypted) mask.Open(1); - Flags = mask; - } - - /// - /// 解析Flags - /// - public void ParseFlagsValue() - { - BitMask32 value = Flags; - IsRawFile = value.Test(0); - IsEncrypted = value.Test(1); + LoadMethod = loadMethod; + Tags = tags; } /// diff --git a/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs b/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs index c1840f8..5b32a8d 100644 --- a/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs +++ b/Assets/YooAsset/Runtime/PatchSystem/PatchManifest.cs @@ -290,7 +290,6 @@ namespace YooAsset // BundleList foreach (var patchBundle in patchManifest.BundleList) { - patchBundle.ParseFlagsValue(); patchBundle.ParseFileName(patchManifest.OutputNameStyle); patchManifest.BundleDic.Add(patchBundle.BundleName, patchBundle); } diff --git a/Assets/YooAsset/Runtime/Services/IDecryptionServices.cs b/Assets/YooAsset/Runtime/Services/IDecryptionServices.cs index bd73343..11ea5b0 100644 --- a/Assets/YooAsset/Runtime/Services/IDecryptionServices.cs +++ b/Assets/YooAsset/Runtime/Services/IDecryptionServices.cs @@ -1,17 +1,42 @@  namespace YooAsset { - public struct DecryptionFileInfo + public struct DecryptFileInfo { + /// + /// 资源包名称 + /// public string BundleName; - public string FileHash; + + /// + /// 文件路径 + /// + public string FilePath; } + /// + /// 解密类服务接口 + /// public interface IDecryptionServices { /// - /// 获取加密文件的数据偏移量 + /// 文件偏移解密方法 /// - ulong GetFileOffset(DecryptionFileInfo fileInfo); + ulong LoadFromFileOffset(DecryptFileInfo fileInfo); + + /// + /// 文件内存解密方法 + /// + byte[] LoadFromMemory(DecryptFileInfo fileInfo); + + /// + /// 文件流解密方法 + /// + System.IO.FileStream LoadFromStream(DecryptFileInfo fileInfo); + + /// + /// 文件流解密的托管缓存大小 + /// + uint GetManagedReadBufferSize(); } } \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/Services/IEncryptionServices.cs b/Assets/YooAsset/Runtime/Services/IEncryptionServices.cs new file mode 100644 index 0000000..0664bfc --- /dev/null +++ b/Assets/YooAsset/Runtime/Services/IEncryptionServices.cs @@ -0,0 +1,37 @@ + +namespace YooAsset +{ + public struct EncryptResult + { + /// + /// 加密后的Bunlde文件加载方法 + /// + public EBundleLoadMethod LoadMethod; + + /// + /// 加密后的文件数据 + /// + public byte[] EncryptedData; + } + + public struct EncryptFileInfo + { + /// + /// 资源包名称 + /// + public string BundleName; + + /// + /// 文件路径 + /// + public string FilePath; + } + + /// + /// 加密服务类接口 + /// + public interface IEncryptionServices + { + EncryptResult Encrypt(EncryptFileInfo fileInfo); + } +} \ No newline at end of file diff --git a/Assets/YooAsset/Runtime/Services/IEncryptionServices.cs.meta b/Assets/YooAsset/Runtime/Services/IEncryptionServices.cs.meta new file mode 100644 index 0000000..3991708 --- /dev/null +++ b/Assets/YooAsset/Runtime/Services/IEncryptionServices.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04491137351983348959c00ec4ee226a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/YooAsset/Runtime/Settings/YooAssetSettings.cs b/Assets/YooAsset/Runtime/Settings/YooAssetSettings.cs index 903709b..c0f5d0c 100644 --- a/Assets/YooAsset/Runtime/Settings/YooAssetSettings.cs +++ b/Assets/YooAsset/Runtime/Settings/YooAssetSettings.cs @@ -24,7 +24,7 @@ namespace YooAsset /// /// 补丁清单文件格式版本 /// - public const string PatchManifestFileVersion = "1.3.3"; + public const string PatchManifestFileVersion = "1.3.4"; /// /// 构建输出文件夹名称