YooAsset源碼閱讀-Downloader篇

YooAsset源碼閱讀-Downloader

繼續 YooAsset 的 Downloader ,本文將詳細介紹如何創建下載器相關代碼

CreateResourceDownloaderByAll

關鍵類

  • PlayModeImpl.cs
  • ResourceDownloaderOperation.cs
  • DownloaderOperation.cs
  • BundleInfo.cs

CreateResourceDownloaderByAll 方法用于創建下載所有需要更新資源的下載器。

關鍵源代碼
// PlayModeImpl.cs Line 110-115
ResourceDownloaderOperation IPlayMode.CreateResourceDownloaderByAll(int downloadingMaxNumber, int failedTryAgain)
{List<BundleInfo> downloadList = GetDownloadListByAll(ActiveManifest);var operation = new ResourceDownloaderOperation(PackageName, downloadList, downloadingMaxNumber, failedTryAgain);return operation;
}// PlayModeImpl.cs Line 245-264
public List<BundleInfo> GetDownloadListByAll(PackageManifest manifest)
{if (manifest == null)return new List<BundleInfo>();List<BundleInfo> result = new List<BundleInfo>(1000);foreach (var packageBundle in manifest.BundleList){var fileSystem = GetBelongFileSystem(packageBundle);if (fileSystem == null)continue;if (fileSystem.NeedDownload(packageBundle)){var bundleInfo = new BundleInfo(fileSystem, packageBundle);result.Add(bundleInfo);}}return result;
}

流程圖

調用
遍歷
每個Bundle
檢查
所有Bundle處理完
CreateResourceDownloaderByAll
GetDownloadListByAll
manifest.BundleList
GetBelongFileSystem
fileSystem.NeedDownload
創建BundleInfo
跳過該Bundle
添加到下載列表
繼續下一個Bundle
返回下載列表
創建ResourceDownloaderOperation
返回下載器

CreateResourceDownloaderByTags

關鍵類

  • PlayModeImpl.cs
  • ResourceDownloaderOperation.cs
  • PackageBundle.cs

CreateResourceDownloaderByTags 方法用于創建下載指定標簽資源的下載器,支持DLC(可下載內容)場景。

關鍵源代碼
// PlayModeImpl.cs Line 116-121
ResourceDownloaderOperation IPlayMode.CreateResourceDownloaderByTags(string[] tags, int downloadingMaxNumber, int failedTryAgain)
{List<BundleInfo> downloadList = GetDownloadListByTags(ActiveManifest, tags);var operation = new ResourceDownloaderOperation(PackageName, downloadList, downloadingMaxNumber, failedTryAgain);return operation;
}// PlayModeImpl.cs Line 265-297
public List<BundleInfo> GetDownloadListByTags(PackageManifest manifest, string[] tags)
{if (manifest == null)return new List<BundleInfo>();List<BundleInfo> result = new List<BundleInfo>(1000);foreach (var packageBundle in manifest.BundleList){var fileSystem = GetBelongFileSystem(packageBundle);if (fileSystem == null)continue;if (fileSystem.NeedDownload(packageBundle)){// 如果未帶任何標記,則統一下載if (packageBundle.HasAnyTags() == false){var bundleInfo = new BundleInfo(fileSystem, packageBundle);result.Add(bundleInfo);}else{// 查詢DLC資源if (packageBundle.HasTag(tags)){var bundleInfo = new BundleInfo(fileSystem, packageBundle);result.Add(bundleInfo);}}}}return result;
}

流程圖

傳入tags數組
遍歷
每個Bundle
檢查
HasAnyTags = false
HasAnyTags = true
匹配
不匹配
處理完成
CreateResourceDownloaderByTags
GetDownloadListByTags
manifest.BundleList
GetBelongFileSystem
fileSystem.NeedDownload
跳過該Bundle
檢查Bundle標簽
無標簽Bundle
統一下載
檢查HasTag匹配
DLC資源
添加到下載列表
跳過該Bundle
創建BundleInfo
添加到結果列表
繼續下一個Bundle
返回下載列表
創建ResourceDownloaderOperation

CreateResourceDownloaderByPaths

關鍵類

  • PlayModeImpl.cs
  • ResourceDownloaderOperation.cs
  • AssetInfo.cs
  • PackageManifest.cs

CreateResourceDownloaderByPaths 方法用于創建下載指定資源路徑及其依賴的下載器,支持遞歸下載選項。

關鍵源代碼
// PlayModeImpl.cs Line 122-127
ResourceDownloaderOperation IPlayMode.CreateResourceDownloaderByPaths(AssetInfo[] assetInfos, bool recursiveDownload, int downloadingMaxNumber, int failedTryAgain)
{List<BundleInfo> downloadList = GetDownloadListByPaths(ActiveManifest, assetInfos, recursiveDownload);var operation = new ResourceDownloaderOperation(PackageName, downloadList, downloadingMaxNumber, failedTryAgain);return operation;
}// PlayModeImpl.cs Line 298-359 (核心邏輯)
public List<BundleInfo> GetDownloadListByPaths(PackageManifest manifest, AssetInfo[] assetInfos, bool recursiveDownload)
{if (manifest == null)return new List<BundleInfo>();// 獲取資源對象的資源包和所有依賴資源包List<PackageBundle> checkList = new List<PackageBundle>();foreach (var assetInfo in assetInfos){if (assetInfo.IsInvalid){YooLogger.Warning(assetInfo.Error);continue;}// 獲取主資源包PackageBundle mainBundle = manifest.GetMainPackageBundle(assetInfo.Asset);if (checkList.Contains(mainBundle) == false)checkList.Add(mainBundle);// 獲取依賴資源包List<PackageBundle> mainDependBundles = manifest.GetAssetAllDependencies(assetInfo.Asset);foreach (var dependBundle in mainDependBundles){if (checkList.Contains(dependBundle) == false)checkList.Add(dependBundle);}// 遞歸下載主資源包內所有資源對象依賴的資源包if (recursiveDownload){foreach (var otherMainAsset in mainBundle.IncludeMainAssets){var otherMainBundle = manifest.GetMainPackageBundle(otherMainAsset.BundleID);if (checkList.Contains(otherMainBundle) == false)checkList.Add(otherMainBundle);List<PackageBundle> otherDependBundles = manifest.GetAssetAllDependencies(otherMainAsset);foreach (var dependBundle in otherDependBundles){if (checkList.Contains(dependBundle) == false)checkList.Add(dependBundle);}}}}// 篩選需要下載的資源包List<BundleInfo> result = new List<BundleInfo>(1000);foreach (var packageBundle in checkList){var fileSystem = GetBelongFileSystem(packageBundle);if (fileSystem == null)continue;if (fileSystem.NeedDownload(packageBundle)){var bundleInfo = new BundleInfo(fileSystem, packageBundle);result.Add(bundleInfo);}}return result;
}

流程圖

AssetInfo數組
遍歷
每個AssetInfo
所有AssetInfo處理完
每個PackageBundle
處理完成
CreateResourceDownloaderByPaths
GetDownloadListByPaths
AssetInfo數組
AssetInfo.IsInvalid?
記錄警告
跳過該資源
獲取主資源包
添加到checkList
獲取依賴資源包
添加依賴到checkList
recursiveDownload?
處理下一個AssetInfo
遞歸處理主資源包內
所有資源的依賴
獲取其他主資源包
獲取其他依賴資源包
添加到checkList
遍歷checkList
GetBelongFileSystem
fileSystem.NeedDownload?
創建BundleInfo
添加到結果
跳過該Bundle
繼續下一個Bundle
返回下載列表
創建ResourceDownloaderOperation

下載器核心機制

ResourceDownloaderOperation 繼承關系

繼承
繼承
繼承
繼承
AsyncOperationBase
異步操作基類
DownloaderOperation
下載器操作基類
ResourceDownloaderOperation
資源下載器
ResourceUnpackerOperation
資源解壓器
ResourceImporterOperation
資源導入器

下載器狀態機

DownloaderOperation 使用狀態機管理下載流程:

InternalStart
驗證下載列表
無效
有效
創建下載器
檢查下載結果
DownloaderOperation.BeginDownload
外部使用
Check
下載列表有效?
Done
Status=Failed
Loading
動態管理下載器池
有失敗的下載?
Done
Status=Failed
所有下載完成?
繼續下載
Done
Status=Succeed

下載器池管理機制

DownloaderOperation 采用動態下載器池來優化下載性能,主要特性:

  1. 最大并發限制:通過 MAX_LOADER_COUNT = 64_downloadingMaxNumber 控制同時下載的文件數量
  2. 失敗重試機制:支持 _failedTryAgain 參數控制失敗重試次數
  3. 動態調度:當有下載器完成時,自動從待下載列表中選擇新的文件開始下載
  4. 暫停/恢復:支持 PauseDownload()ResumeDownload() 控制下載狀態
  5. 進度回調:提供詳細的下載進度、錯誤、開始等事件回調

需要注意 DownloaderOperation.InternalUpdate 方法中的關鍵邏輯:

// 動態創建新的下載器到最大數量限制
// 注意:如果期間有下載失敗的文件,暫停動態創建下載器
if (_bundleInfoList.Count > 0 && _failedList.Count == 0)
{if (_isPause)return;if (_downloaders.Count < _downloadingMaxNumber){int index = _bundleInfoList.Count - 1;var bundleInfo = _bundleInfoList[index];var downloader = bundleInfo.CreateDownloader(_failedTryAgain);downloader.StartOperation();this.AddChildOperation(downloader);_downloaders.Add(downloader);_bundleInfoList.RemoveAt(index);}
}

從用戶調用到UnityWebRequest的完整調用鏈

看完上面的分析,我覺得還需要把整個調用鏈梳理清楚,這樣更容易理解整個下載流程。

調用鏈概述

用戶調用下載器到最終發起UnityWebRequest的完整調用鏈是這樣的:

用戶代碼 → downloader.BeginDownload() → OperationSystem.Update() → DownloaderOperation.InternalUpdate() 
→ BundleInfo.CreateDownloader() → DefaultCacheFileSystem.DownloadFileAsync() → DownloadPackageBundleOperation
→ DownloadCenter.DownloadFileAsync() → UnityDownloadFileOperation → UnityWebFileRequestOperation → UnityWebRequest

詳細調用鏈分析

1. 用戶入口點
// 用戶代碼
var downloader = package.CreateResourceDownloaderByAll(10, 3);
downloader.BeginDownload(); // 開始下載
2. BeginDownload → InternalUpdate
// DownloaderOperation.cs
public void BeginDownload()
{// 開始下載會調用 OperationSystem.StartOperationOperationSystem.StartOperation(PackageName, this);
}// OperationSystem每幀會調用
internal override void InternalUpdate()
{// 在Loading狀態時會動態創建下載器if (_bundleInfoList.Count > 0 && _failedList.Count == 0){var bundleInfo = _bundleInfoList[index];var downloader = bundleInfo.CreateDownloader(_failedTryAgain); // 關鍵調用downloader.StartOperation();this.AddChildOperation(downloader);}
}
3. BundleInfo.CreateDownloader
// BundleInfo.cs Line 39-44
public FSDownloadFileOperation CreateDownloader(int failedTryAgain)
{DownloadFileOptions options = new DownloadFileOptions(failedTryAgain);options.ImportFilePath = _importFilePath;return _fileSystem.DownloadFileAsync(Bundle, options); // 委托給FileSystem
}
4. DefaultCacheFileSystem.DownloadFileAsync
// DefaultCacheFileSystem.cs Line 172-191
public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options)
{// 獲取下載地址string mainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);string fallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);options.SetURL(mainURL, fallbackURL);// 創建具體的下載操作var downloader = new DownloadPackageBundleOperation(this, bundle, options);return downloader;
}
5. DownloadPackageBundleOperation
// DownloadPackageBundleOperation.cs Line 58-72
if (_steps == ESteps.CreateRequest)
{string url = GetRequestURL();// 委托給DownloadCenter創建Unity下載器_unityDownloadFileOp = _fileSystem.DownloadCenter.DownloadFileAsync(Bundle, url);_steps = ESteps.CheckRequest;
}
6. DownloadCenter → UnityDownloadFileOperation
// DownloadCenterOperation.cs
public UnityDownloadFileOperation DownloadFileAsync(PackageBundle bundle, string url)
{// 根據斷點續傳等條件創建不同的下載器if (bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize){return new ResumeDownloadOperation(_fileSystem, bundle, url);}else{return new NormalDownloadOperation(_fileSystem, bundle, url);}
}
7. UnityDownloadFileOperation → UnityWebRequest
// UnityWebFileRequestOperation.cs Line 72-81
private void CreateWebRequest()
{DownloadHandlerFile handler = new DownloadHandlerFile(_fileSavePath);handler.removeFileOnAbort = true;// 最終創建UnityWebRequest_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);_webRequest.timeout = _timeout;_webRequest.downloadHandler = handler;_webRequest.disposeDownloadHandlerOnDispose = true;// 發起網絡請求_requestOperation = _webRequest.SendWebRequest();
}

完整調用鏈流程圖

downloader.BeginDownload
OperationSystem.Update
bundleInfo.CreateDownloader
_fileSystem.DownloadFileAsync
new DownloadPackageBundleOperation
DownloadCenter.DownloadFileAsync
創建具體下載器
CreateWebRequest
_webRequest.SendWebRequest
用戶代碼
DownloaderOperation
InternalUpdate循環
BundleInfo
DefaultCacheFileSystem
DownloadPackageBundleOperation
DownloadCenterOperation
UnityDownloadFileOperation
UnityWebFileRequestOperation
UnityWebRequest
關鍵步驟說明
用戶調用BeginDownload啟動下載
OperationSystem每幀Update驅動
BundleInfo適配不同FileSystem
FileSystem創建具體下載操作
DownloadCenter管理并發控制
UnityWebRequest執行實際網絡請求

關鍵調用點解析

1. 責任分離設計
  • DownloaderOperation:管理下載器池和并發控制
  • BundleInfo:適配器,統一不同FileSystem的接口
  • DefaultCacheFileSystem:處理URL獲取和參數配置
  • DownloadPackageBundleOperation:狀態機管理,重試邏輯
  • DownloadCenter:并發限制和下載器復用
  • UnityDownloadFileOperation:Unity網絡請求的具體實現
2. 異步調用鏈

整個調用鏈是異步的,通過 OperationSystem 的 Update 循環驅動:

// 主要更新循環
YooAsset.Update() → OperationSystem.Update() → AsyncOperationBase.Update()InternalUpdate()
3. 錯誤處理和重試

在調用鏈的每一層都有相應的錯誤處理:

  • DownloaderOperation:失敗隔離策略
  • DownloadPackageBundleOperation:重試邏輯和超時處理
  • UnityWebRequest:網絡層錯誤處理

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92025.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92025.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92025.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

豆包新模型與 PromptPilot 實操體驗測評,AI 輔助創作的新范式探索

摘要&#xff1a;在 AI 技術飛速發展的當下&#xff0c;各類大模型及輔助工具層出不窮&#xff0c;為開發者和創作者帶來了全新的體驗。2025 年 7 月 30 日廈門站的火山方舟線下 Meetup&#xff0c;為我們提供了近距離接觸豆包新模型與 PromptPilot 的機會。本次重點體驗了實驗…

深入探討AI在測試領域的三大核心應用:自動化測試框架、智能缺陷檢測和A/B測試優化,并通過代碼示例、流程圖和圖表詳細解析其實現原理和應用場景。

引言隨著人工智能技術的飛速發展&#xff0c;軟件測試領域正在經歷一場深刻的變革。AI技術不僅提高了測試效率&#xff0c;還增強了測試的準確性和覆蓋范圍。本文將深入探討AI在測試領域的三大核心應用&#xff1a;自動化測試框架、智能缺陷檢測和A/B測試優化&#xff0c;并通過…

音視頻學習筆記

0.vs應用其他庫配置1基礎 1.1視頻基礎 音視頻錄制原理音視頻播放原理圖像表示rgb圖像表示yuvhttps://blog.51cto.com/u_7335580/2059670 https://blog.51cto.com/cto521/1944224 https://blog.csdn.net/mandagod/article/details/78605586?locationNum7&fps1 視頻主要概念…

LLM隱藏層狀態: outputs.hidden_states 是 MLP Residual 還是 Layer Norm

outputs.hidden_states 是 MLP Residual 還是 Layer Norm outputs.hidden_states 既不是單純的 MLP Residual,也不是單純的 Layer Norm,而是每一層所有組件(包括 Layer Norm、注意力、MLP、殘差連接等)處理后的最終隱藏狀態。具體需結合 Transformer 層的結構理解: 1. T…

XML 用途

XML 用途 引言 XML&#xff08;可擴展標記語言&#xff09;是一種用于存儲和傳輸數據的標記語言。自1998年推出以來&#xff0c;XML因其靈活性和可擴展性&#xff0c;在眾多領域得到了廣泛應用。本文將詳細介紹XML的用途&#xff0c;幫助讀者全面了解這一重要技術。 一、數據存…

亞馬遜撤離Google購物廣告:重構流量生態的戰略博弈

戰略突變&#xff1a;從漸進收縮到全面退潮的背后邏輯亞馬遜在2025年7月突然全面停止Google Shopping廣告投放&#xff0c;這場看似 abrupt 的決策實則經歷了一年多的戰略鋪墊&#xff0c;從2024年Q1開始的預算削減&#xff0c;到2025年Q2美國市場支出減半&#xff0c;直至核心…

【QT】常?控件詳解(三)常用按鈕控件PushButton RadioButton CheckButton Tool Button

文章目錄前言一、PushButton1.1 QAbstractButton1.2 添加圖標的按鈕1.3 給按鈕添加快捷鍵1.4 代碼?例:按鈕的重復觸發二、 RadioButtion2.1簡介2.2 幾個槽函數 click,press,release, toggled 的區別2.2 模擬分組點餐三、 CheckBox四、Tool Button&#x1f6a9;總結前言 一、P…

數據結構:反轉鏈表(reverse the linked list)

目錄 通過交換元素值實現反轉&#xff08;reverse by swapping elements&#xff09; 滑動指針&#xff08;sliding pointers&#xff09; 使用滑動指針反轉鏈表&#xff08;Reversing a Linked List using Sliding Pointers&#xff09; 對比分析 如何用遞歸&#xff08;R…

【C#】基于SharpCompress實現壓縮包解壓功能

1.SharpCompress安裝 在vs的nuget下搜索安裝SharpCompress&#xff0c;如圖所示2.解壓縮包功能實現 /// <summary> /// 解壓壓縮包 /// </summary> /// <param name"filePath">壓縮包文件路徑</param> /// <param name"directoryPat…

mybatis連接PGSQL中對于json和jsonb的處理方法

pgsql數據庫表字段設置了jsonb格式&#xff1b;在java的實體里使用String或者對象轉換會一直提示一個錯誤&#xff1a; Caused by: org.postgresql.util.PSQLException: ERROR: column “xx” is of type jsonb but expression is of type character varying 需要加一個轉換方法…

Spring AI Alibaba Graph 深度解析:原理、架構與應用實踐

1. 引言概述 1.1 什么是 Spring AI Alibaba Graph Spring AI Alibaba Graph 是阿里云團隊基于 Spring AI 生態開發的一個強大的工作流編排框架&#xff0c;專門用于構建復雜的 AI 應用。它采用聲明式編程模型&#xff0c;通過圖結構來定義和管理 AI 工作流&#xff0c;讓開發…

C++少兒編程(二十一)—軟件執行流程

讓我們將以下程序視為用C編寫的示例程序。步驟1&#xff1a;預處理器將源代碼轉換為擴展代碼。當您運行程序時&#xff0c;源代碼首先被發送到稱為預處理器的工具。預處理器主要做兩件事&#xff1a;它會從程序中刪除注釋。它擴展了預處理器指令&#xff0c;如宏或文件包含。它…

精通Webpack搭建Vue2.0項目腳手架指南

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;在Web應用程序開發中&#xff0c;Vue 2.0因其虛擬DOM、單文件組件、增強的生命周期鉤子和Vuex及Vue Router狀態管理與路由解決方案&#xff0c;成為了提高開發效率和代碼組織性的關鍵。Webpack作為必不可少的模…

無償分享120套開源數據可視化大屏H5模板

數據可視化跨越了語言、技術和專業的邊界&#xff0c;是能夠推動實現跨界溝通&#xff0c;實現國際間跨行業的創新的工具。正如畫家用顏料表達自我&#xff0c;作者用文字講述故事&#xff0c;而統計人員用數字溝通 ...... 同樣&#xff0c;數據可視化的核心還是傳達信息。而設…

Qt按鍵響應

信號與槽機制是一個非常強大的事件通信機制&#xff0c;是 Qt 最核心的機制之一&#xff0c;初學者掌握它之后&#xff0c;幾乎可以做任何交互操作。信號&#xff08;Signal&#xff09; 是一種“事件”或“通知”&#xff0c;比如按鈕被點擊、文本改變、窗口關閉等。 槽&#…

【Git】常見命令整理

Git分區與操作關系&#xff1a;Working Directory&#xff08;工作區&#xff0c;對于本地的編輯和修改在此進行&#xff09;->Staging Area&#xff08;暫存區/Index&#xff0c;在工作區進行git add操作后的位置&#xff09;->Git Repository&#xff08;本地倉庫&…

Linux-Shell腳本基礎用法

1.變量定義變量命名規則&#xff1a;可以包含字母&#xff0c;數字&#xff0c;下劃線&#xff0c;首字母不能用數字開頭&#xff0c;中間不能又空格&#xff1b;為變量賦值等號之間不能為空格&#xff1b;變量命名不能使用標點符號&#xff0c;不能使用bash的關鍵字&#xff1…

JS中的Map和WeakMap區別和聯系

JavaScript 中 Map 與 WeakMap 的區別、聯系及示例核心區別特性MapWeakMap鍵的類型允許任意類型的鍵&#xff08;對象、原始值&#xff09;鍵必須是對象&#xff08;非原始值&#xff09;垃圾回收強引用鍵 → 阻止垃圾回收弱引用鍵 → 不影響垃圾回收可遍歷性支持遍歷&#xff…

Linux 環境 libpq加載異常導致psql 連接 PostgreSQL 庫失敗失敗案例

文章目錄局點現象定位結論局點環境補充知識點如下庫文件加載順序關鍵事實&#xff1a;您系統中的證據&#xff1a;優先級對比表&#xff1a;解決方案強化&#xff1a;最終檢查&#xff1a;本局點解決方法局點現象 數據庫 mdm 升級失敗檢查日志, 發現是由于 psql 連接數據庫報錯…

C# XML 文件

在 C# 中處理 XML 文件是非常常見的操作&#xff0c;可以使用System.Xml命名空間中的類來實現。以下是一些常用的 XML 操作示例&#xff1a; 手冊鏈接&#xff1a; System.Xml 命名空間 XmlDocument 創建一個xml數據格式的文檔 XmlDocument xml new XmlDocument(); Xml…