注意
:考慮到熱更新的內容比較多,我將熱更新的內容分開,并全部整合放在【unity游戲開發——熱更新】專欄里,感興趣的小伙伴可以前往逐一查看學習。
文章目錄
- 前言
- 1、什么是YooAsset?
- 2、系統需求
- 3、系統特點
- 一、下載安裝
- 1、方法一:通過PackageManager安裝(`推薦`)
- 2、方法二:通過Packages清單安裝
- 3、方法三:通過Github下載安裝
- 二、導入示例工程
- 三、YooAsset工具窗口介紹
- 1、Home Page:跳轉至 YooAsset 官方主頁
- 2、AssetBundle Collector:資源配置界面
- 2.1 頂部功能欄細節
- 2.2 全局設置項解析
- 2.3 包裹設置項說明
- 2.4 資源分組
- (1)Group Active:分組激活規則
- (2)Group Name:定義分組名稱(如 battle),標識資源分組用途。
- (3)Grouper Desc:添加分組備注信息,說明分組內容,方便團隊協作理解。
- (4)Asset Tags:為分組內資源添加分類標簽(多標簽用分號分隔,如 level1;level2),便于資源篩選。
- 2.5 搜集器
- (1)Collect Path:指定資源收集路徑,可設置文件夾或單個文件,限定收集范圍。
- (2)Collector Type:定義收集器類型:
- (3)AddressRule:可尋址規則()。內置如 AddressByFileName(按文件名定位)
- (4)PackRule:打包規則
- (5)FilterRule:過濾收集的資源類型。內置如 CollectScene(只收集場景文件),示例:
- (6)UserData:自定義數據,輔助定制 AddressRule 和 PackRule,滿足個性化需求。
- (7)Asset Tags:為搜集器內資源添加分類標簽,便于后續資源管理與篩選。
- 3、AssetBundle Builder:資源構建界面
- 3.1 界面功能模塊
- (1)Build Package:資源包裹列表,通過下拉選擇確定需構建的資源包裹范圍。
- (2)Build Pipeline:構建管線的列表,下拉選擇要使用的構建管線。
- (3)Build Output:構建輸出目錄,根據Unity當前平臺劃分構建結果,便于管理不同平臺資源。
- (4)Build Version:設置構建的資源包版本,用于標識補丁包等內容。
- (5)Clear Build Cache:清理構建緩存,勾選則重新構建所有資源包;不勾選啟用增量打包,提升構建速度。
- (6)Use Asset Depend DB:開啟后使用資源依賴關系數據庫,加快資源收集與構建效率。
- (7)Encryption:加密類列表
- (8)Compression:設置資源包壓縮方式,優化包體大小。
- (9)File Name Style:定義輸出資源包文件名樣式
- (10)Copy Buildin File Option:首包資源拷貝方式
- 3.2 構建操作與結果
- (1)構建執行:點擊“構建”按鈕啟動多節點流程,任一節點錯誤則構建失敗,錯誤信息可在控制臺查看。
- (2)補丁包:構建成功后,輸出目錄生成以“`Build Version`資源版本號”命名的補丁包文件夾,包含:
- (3)構建報告:DefaultPackage_xxx.report,可通過構建報告窗口查看詳細構建信息。
- (4)重要概念與注意事項
- 4、AssetBundle Reporter:構建報告界面
- 5、AssetBundle Debugger:調試工具
- 5.1 調試器核心功能
- 5.2 真機遠程調試注意事項
- 5.3 資源對象列表視圖
- 6、AssetArt Scanner:資產掃描器
- 6.1 工具界面組成
- 6.2 基礎操作按鈕
- 6.3 掃描器配置項詳解
- 6.4 掃描器檢視界面
- 6.5 掃描器接口擴展
- 7、AssetArt Reporter:資產掃描報告
- 7.1 工具介紹
- 7.2 搜索欄支持
- 四、YooAsset資源系統的運行模式
- 1、編輯器模擬模式 (EditorSimulateMode)
- 2、單機運行模式 (OfflinePlayMode)
- 3、聯機運行模式 (HostPlayMode)
- 4、Web運行模式 (WebPlayMode)
- 5、自定義運行模式 (CustomPlayMode)
- 五、YooAsset資源熱更新實踐
- 1、導入資源
- 2、將圖片1進行打包
- 3、復制version文件和bytes文件到我們的流文件夾
- 4、開啟允許從http下載
- 5、復制前面打包出來的資源到本地資源服務器,啟動本地資源服務器
- 6、手寫熱更新流程代碼
- 7、掛載腳本運行游戲,可以看到熱更和加載成功
- 8、其他加載資源方式
- 8.1 使用委托異步加載資源
- 8.2 協程加載資源
- 8.3 Task加載資源
- 9、場景加載
- 10、預制體加載和創建
- 11、加載圖片子對象切片
- 12、卸載相關
- 12.1 回收不再使用的資源
- 12.2 強制回收所有資源
- 12.3 嘗試卸載指定的資源
- 六、YooAsset資源加密解密
- 1、加密資源對象
- 2、解密資源對象
- 3、使用解密對象解密加密的資源
- 專欄推薦
- 完結
前言
1、什么是YooAsset?
YooAsset 是一款輕量級、高性能的 Unity 資源管理系統,專注于簡化資源加載、打包、更新等流程,尤其適合中小型游戲或應用開發。
- 官方文檔:https://www.yooasset.com/docs/Introduce
- Github地址:https://github.com/tuyoogame/YooAsset
2、系統需求
-
支持版本: Unity2019.4 & Unity2020.3 & Unity2021.3 & Unity2022.3 & Unity6.0
-
支持平臺: Windows、OSX、Android、iOS、WebGL
-
開發環境: .NET4.x
3、系統特點
- 可擴展文件系統
完美支持微信小游戲和抖音小游戲等特殊平臺。支持接入虛擬文件系統,支持自定義各類需求。
- 構建管線無縫切換
支持傳統的內置構建管線,也支持可編程構建管線(SBP)。
- 支持分布式構建
支持分工程構建,支持工程里分內容構建,很方便支持游戲模組(MOD)。
- 支持可尋址資源定位
默認支持完整路徑的資源定位,也支持可尋址資源定位,不需要繁瑣的過程即可高效的配置尋址路徑。
- 安全高效的分包方案
基于資源標簽的分包方案,自動對依賴資源包進行分類,避免人工維護成本。可以非常方便的實現零資源安裝包,或者全量資源安裝包。
- 強大靈活的打包系統
可以自定義打包策略,自動分析依賴實現資源零冗余,基于資源對象的資源包依賴管理方案,天然的避免了資源包之間循環依賴的問題。
- 基于引用計數方案
基于引用計數的管理方案,可以幫助我們實現安全的資源卸載策略,更好的對內存管理,避免資源對象冗余。還有強大的分析器可幫助發現潛在的資源泄漏問題。
- 多種模式自由切換
編輯器模擬模式,單機運行模式,聯機運行模式,Web運行模式。在編輯器模擬模式下,可以不構建資源包來模擬真實環境,在不修改任何代碼的情況下,可以自由切換到其它模式。
-
強大安全的加載系統
- 異步加載 支持協程,Task,委托等多種異步加載方式。
- 同步加載 支持同步加載和異步加載混合使用。
- 邊玩邊下載 在加載資源對象的時候,如果資源對象依賴的資源包在本地不存在,會自動從服務器下載到本地,然后再加載資源對象。
- 多線程下載 支持斷點續傳,自動驗證下載文件,自動修復損壞文件。
- 多功能下載器 可以按照資源分類標簽創建下載器,也可以按照資源對象創建下載器。可以設置同時下載文件數的限制,設置下載失敗重試次數,設置下載超時判定時間。多個下載器同時下載不用擔心文件重復下載問題,下載器還提供了下載進度以及下載失敗等常用接口。
-
原生格式文件管理
支持原生文件構建關系,可以很方便的實現原生文件的版本管理和下載。
- 靈活多變的版本管理
支持線上版本快速回退,支持區分審核版本,測試版本,線上版本,支持灰度更新及測試。
- 多平臺的完美適配
支持安卓,蘋果,PC等常規平臺,支持網頁運行。2.x版本完美適配了微信小游戲平臺和抖音小游戲平臺。
一、下載安裝
1、方法一:通過PackageManager安裝(推薦
)
打開管理界面 Edit/Project Settings/Package Manager
// 輸入以下內容(國際版)
Name: package.openupm.com
URL: https://package.openupm.com
Scope(s): com.tuyoogame.yooasset
添加倉庫配置
打開管理界面 Edit/Windows/Package Manager,點擊安裝
2、方法二:通過Packages清單安裝
直接修改項目根目錄Packages文件夾下的清單文件manifest.json
{"dependencies": {"com.tuyoogame.yooasset": "2.x.x",......},"scopedRegistries": [{"name": "package.openupm.com","url": "https://package.openupm.com","scopes": ["com.tuyoogame.yooasset"]}]
}
3、方法三:通過Github下載安裝
Github地址:https://github.com/tuyoogame/YooAsset
在發布的Release版本中,選擇最新版本下載Source Code壓縮包。解壓后將Assets/YooAsset目錄拷貝到項目Assets文件夾中
二、導入示例工程
三、YooAsset工具窗口介紹
1、Home Page:跳轉至 YooAsset 官方主頁
2、AssetBundle Collector:資源配置界面
收集項目資源,確定哪些資源需要打包成 AssetBundle。
2.1 頂部功能欄細節
-
Fix 修復按鈕:當配置中的文件夾位置變動時,修正資源路徑關聯,確保資源引用正常。比如默認找不到資源路徑,點擊修復按鈕后找到了
-
Import 導入按鈕:導入保存的 XML 配置文件,快速復用歷史配置,減少重復操作。
-
Export 導出按鈕:將當前配置數據導出為 XML 文件,便于備份、團隊協作共享配置。
2.2 全局設置項解析
-
Show Package:控制是否展示資源包列表視圖,勾選后直觀呈現項目資源包結構。
-
Show Editor Alias:是否顯示為中文模式。
-
Unique Bundle Name:資源包名追加
PackageName
作為前綴。當有多個Package
的時候,強烈建議開啟此項!
2.3 包裹設置項說明
- Enable Addressable:啟用可尋址資源定位系統,支持代碼加載資源,同時兼容全路徑加載方式。
- Location To Lower:使資源定位地址大小寫不敏感,簡化資源加載時的地址匹配邏輯。
- Include Asset GUID:在資源清單中記錄資源 GUID 信息,精準追蹤管理資源。
- Auto Collect Shaders:自動將所有著色器打包到獨立資源包,優化著色器管理與加載效率。
- File Ignore Rule:設置全局文件忽略規則(支持擴展),如原生文件配置可選擇
RawFileIgnoreRule
過濾特定文件。
2.4 資源分組
(1)Group Active:分組激活規則
- EnableGroup(啟用分組)
- DisableGroup(禁用分組)
- 支持自定義擴展,示例代碼:
//自定義擴展范例 public class DisableGroup : IActiveRule { public bool IsActiveGroup(GroupData groupData) { return false; } }
(2)Group Name:定義分組名稱(如 battle),標識資源分組用途。
(3)Grouper Desc:添加分組備注信息,說明分組內容,方便團隊協作理解。
(4)Asset Tags:為分組內資源添加分類標簽(多標簽用分號分隔,如 level1;level2),便于資源篩選。
2.5 搜集器
(1)Collect Path:指定資源收集路徑,可設置文件夾或單個文件,限定收集范圍。
(2)Collector Type:定義收集器類型:
- MainAssetCollector:收集主資源并寫入清單,支持代碼加載。
- StaticAssetCollector:收集主資源但不寫入清單,用于定制化打包。
- DependAssetCollector:收集依賴資源,未引用依賴自動剔除。
(3)AddressRule:可尋址規則()。內置如 AddressByFileName(按文件名定位)
- AddressByFileName 以文件名為定位地址。
- AddressByFilePath 以文件路徑為定位地址。
- AddressByGrouperAndFileName 以分組名+文件名為定位地址。
- AddressByFolderAndFileName 以文件夾名+文件名為定位地址。
- 支持自定義,示例:
public class AddressByFileName : IAddressRule { string GetAssetAddress(AddressRuleData data) { return Path.GetFileNameWithoutExtension(data.AssetPath); } }
(4)PackRule:打包規則
- PackSeparately 以文件路徑作為資源包名,每個資源文件單獨打包。
- PackDirectory 以文件所在的文件夾路徑作為資源包名,該文件夾下所有文件打進一個資源包。
- PackTopDirectory 以收集器下頂級文件夾為資源包名,該文件夾下所有文件打進一個資源包。
- PackCollector 以收集器路徑作為資源包名,收集的所有文件打進一個資源包。
- PackGroup 以分組名稱作為資源包名,收集的所有文件打進一個資源包。
- PackRawFile 目錄下的資源文件會被處理為原生資源包。
- 支持自定義,示例:
public class PackDirectory : IPackRule { PackRuleResult GetPackRuleResult(PackRuleData data) { string bundleName = Path.GetDirectoryName(data.AssetPath); return new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); } }
(5)FilterRule:過濾收集的資源類型。內置如 CollectScene(只收集場景文件),示例:
- CollectAll 收集目錄下的所有資源文件
- CollectScene 只收集目錄下的場景文件
- CollectPrefab 只收集目錄下的預制體文件
- CollectSprite 只收集目錄下的精靈類型的文件
- 支持自定義,示例:
//自定義擴展范例 public class CollectScene : IFilterRule {public bool IsCollectAsset(FilterRuleData data){return Path.GetExtension(data.AssetPath) == ".unity";} }
(6)UserData:自定義數據,輔助定制 AddressRule 和 PackRule,滿足個性化需求。
(7)Asset Tags:為搜集器內資源添加分類標簽,便于后續資源管理與篩選。
3、AssetBundle Builder:資源構建界面
構建工具,用于生成 AssetBundle 包,配置打包參數。
3.1 界面功能模塊
(1)Build Package:資源包裹列表,通過下拉選擇確定需構建的資源包裹范圍。
(2)Build Pipeline:構建管線的列表,下拉選擇要使用的構建管線。
- EditorSimulateBuildPipeline:編輯器模擬構建管線,生成資源清單但不生成Bundle文件,用于模擬真實打包環境。
- BuiltinBuildPipeline:內置構建管線,常規構建使用。
- ScriptableBuildPipeline:可編程構建管線(
Unity 2021.3+開始推薦使用該構建管線
),允許開發者控制打包流程。 - RawFileBuildPipeline:原生文件構建管線,處理Unity無法識別的資源(如FMOD音頻文件)。
(3)Build Output:構建輸出目錄,根據Unity當前平臺劃分構建結果,便于管理不同平臺資源。
(4)Build Version:設置構建的資源包版本,用于標識補丁包等內容。
(5)Clear Build Cache:清理構建緩存,勾選則重新構建所有資源包;不勾選啟用增量打包,提升構建速度。
(6)Use Asset Depend DB:開啟后使用資源依賴關系數據庫,加快資源收集與構建效率。
(7)Encryption:加密類列表
支持自定義加密(需實現 IEncryptionServices 接口),包含文件偏移、內存、流等解密加載方式。
(8)Compression:設置資源包壓縮方式,優化包體大小。
(9)File Name Style:定義輸出資源包文件名樣式
- HashName(哈希值)
- BundleName(資源包名)
- BundleName_HashName(資源包名+哈希值)。
(10)Copy Buildin File Option:首包資源拷貝方式
- None:不拷貝文件。
- ClearAndCopyAll:清空后拷貝所有文件。
- ClearAndCopyByTags:清空后按資源標簽拷貝。
- OnlyCopyAll:不清空直接拷貝所有文件。
- OnlyCopyByTags:不清空直接按標簽拷貝。
3.2 構建操作與結果
(1)構建執行:點擊“構建”按鈕啟動多節點流程,任一節點錯誤則構建失敗,錯誤信息可在控制臺查看。
(2)補丁包:構建成功后,輸出目錄生成以“Build Version
資源版本號”命名的補丁包文件夾,包含:
- DefaultPackage.version:資源版本文件。
- DefaultPackage_xxx.hash:記錄資源清單哈希值。
- DefaultPackage_xxx.json:Json格式,用于預覽信息。
- DefaultPackage_xxx.bytes:二進制格式,供程序讀取加載。
(3)構建報告:DefaultPackage_xxx.report,可通過構建報告窗口查看詳細構建信息。
(4)重要概念與注意事項
-
增量構建:利用Unity資源構建緩存,避免重復構建,提升打包效率。也就是不勾選
Clear Build Cache
。
-
首包資源:構建應用時打入首包的資源,存放于 StreamingAssets/yoo/ 目錄,支持熱更新。也就是選擇
Copy Buildin File Option首包資源拷貝方式
。
-
Jenkins自動化構建:參考示例代碼配置構建參數(如輸出目錄、版本、加密等),通過代碼執行構建流程,實現自動化。
如果需要自動化構建,可以參考如下代碼范例:
下面是使用內置構建管線來構建資源包的代碼。private static void BuildInternal(BuildTarget buildTarget) {Debug.Log($"開始構建 : {buildTarget}");var buildoutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();var streamingAssetsRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot();// 構建參數BuiltinBuildParameters buildParameters = new BuiltinBuildParameters();buildParameters.BuildOutputRoot = buildoutputRoot;buildParameters.BuildinFileRoot = streamingAssetsRoot;buildParameters.BuildPipeline = EBuildPipeline.BuiltinBuildPipeline.ToString();buildParameters.BuildBundleType = (int)EBuildBundleType.AssetBundle; //必須指定資源包類型buildParameters.BuildTarget = BuildTarget;buildParameters.PackageName = "DefaultPackage";buildParameters.PackageVersion = "1.0";buildParameters.VerifyBuildingResult = true;buildParameters.EnableSharePackRule = true; //啟用共享資源構建模式,兼容1.5x版本buildParameters.FileNameStyle = EFileNameStyle.HashName;buildParameters.BuildinFileCopyOption = EBuildinFileCopyOption.None;buildParameters.BuildinFileCopyParams = string.Empty;buildParameters.EncryptionServices = CreateEncryptionInstance();buildParameters.CompressOption = ECompressOption.LZ4;buildParameters.ClearBuildCacheFiles = false; //不清理構建緩存,啟用增量構建,可以提高打包速度!buildParameters.UseAssetDependencyDB = true; //使用資源依賴關系數據庫,可以提高打包速度!// 執行構建BuiltinBuildPipeline pipeline = new BuiltinBuildPipeline();var buildResult = pipeline.Run(buildParameters, true);if (buildResult.Success){Debug.Log($"構建成功 : {buildResult.OutputPackageDirectory}");}else{Debug.LogError($"構建失敗 : {buildResult.ErrorInfo}");} }// 從構建命令里獲取參數示例 private static string GetBuildPackageName() {foreach (string arg in System.Environment.GetCommandLineArgs()){if (arg.StartsWith("buildPackage"))return arg.Split("="[0])[1];}return string.Empty; }
-
SBP構建管線注意事項:需設置內置著色器資源包名稱,且與自動收集的著色器資源包名一致,確保構建正確。
private static void BuildInternal(BuildTarget buildTarget) {// 構建參數ScriptableBuildParameters buildParameters = new ScriptableBuildParameters();......buildParameters.BuiltinShadersBundleName = GetBuiltinShaderBundleName(); }/// <summary> /// 內置著色器資源包名稱 /// 注意:和自動收集的著色器資源包名保持一致! /// </summary> private string GetBuiltinShaderBundleName() {var uniqueBundleName = AssetBundleCollectorSettingData.Setting.UniqueBundleName;var packRuleResult = DefaultPackRule.CreateShadersPackRuleResult();return packRuleResult.GetBundleName(PackageName, uniqueBundleName); }
4、AssetBundle Reporter:構建報告界面
生成構建報告,展示 AssetBundle 依賴關系、大小等信息,便于分析優化。
YooAsset 構建報告工具支持查看概覽信息、資源對象視圖、資源包視圖,且僅適配 Unity 2019.4+ 版本。要import后選擇打包出來的report文件才能查看。各視圖功能如下:
5、AssetBundle Debugger:調試工具
用于排查 AssetBundle 加載、依賴錯誤等運行時問題。
5.1 調試器核心功能
- 作用:在游戲運行時實時監控資源包加載狀態,追蹤資源對象引用計數,輔助定位資源泄漏問題。
- 資源泄漏定位:通過引用計數與資源包卸載條件,快速識別未釋放的資源。
- 性能優化:分析加載耗時與異步任務執行鏈,優化資源加載策略。
- 依賴關系驗證:校驗資源包依賴關系,避免冗余加載或錯誤引用。
5.2 真機遠程調試注意事項
在構建安裝包的時候,需要勾選上Development Build和Autoconnect Profiler
5.3 資源對象列表視圖
該頁面展示了當前加載的所有資源對象,以及加載耗時,加載狀態,引用計數等數據。
Depend Bundles 是選中的資源對象加載所依賴的資源包列表!
6、AssetArt Scanner:資產掃描器
掃描項目美術資源(如模型、貼圖),檢測格式、尺寸等規范問題。
6.1 工具界面組成
- 左側:資產掃描器列表,顯示所有可用掃描器。
- 中間:選中掃描器的配置界面,設置掃描規則與參數。
- 右側:掃描器參數檢視界面,展示自定義掃描器的專屬配置。
6.2 基礎操作按鈕
- 導入按鈕:加載保存的 XML 配置文件,復用歷史掃描規則。
- 導出按鈕:將當前配置導出為 XML 文件,便于備份或團隊共享。
- 掃描所有按鈕:執行全部掃描器任務,生成多份掃描報告。
6.3 掃描器配置項詳解
- Scanner Name:定義掃描器名稱(如 TextureScanner),標識掃描器功能。
- Scanner Desc:添加掃描器備注信息,說明掃描用途或規則。
- Scanner Schema:關聯掃描器模式文件(繼承 ScannerSchema 的 ScriptableObject)。
- Output Folder:設置報告文件輸出目錄,默認為 Assets/ScanReports。
- Collector:指定掃描路徑,可配置多個文件夾或文件范圍。
6.4 掃描器檢視界面
- 功能:開發者實現自定義掃描器時,可編寫專屬參數檢視面板。
- 實現方式:繼承 SchemaInspector 類,通過 EditorGUI 繪制可視化配置項。
6.5 掃描器接口擴展
繼承基類ScannerSchema并實現虛擬方法。ScannerSchema實際上是可序列化類型。
public abstract class ScannerSchema : ScriptableObject
{/// <summary>/// 獲取用戶指南信息/// </summary>public abstract string GetUserGuide();/// <summary>/// 運行生成掃描報告/// </summary>public abstract ScanReport RunScanner(AssetArtScanner scanner);/// <summary>/// 修復掃描結果/// </summary>public abstract void FixResult(List<ReportElement> fixList);/// <summary>/// 創建檢視面板/// </summary>public virtual SchemaInspector CreateInspector();
}
太空戰機DEMO里實現了一個非常簡單的紋理掃描器,可以直接閱讀源碼來快速學習。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace YooAsset.Editor
{public abstract class ScannerSchema : ScriptableObject{/// <summary>/// 獲取用戶指南信息/// </summary>public abstract string GetUserGuide();/// <summary>/// 運行生成掃描報告/// </summary>public abstract ScanReport RunScanner(AssetArtScanner scanner);/// <summary>/// 修復掃描結果/// </summary>public abstract void FixResult(List<ReportElement> fixList);/// <summary>/// 創建檢視面板/// </summary>public virtual SchemaInspector CreateInspector(){return null;}}
}
7、AssetArt Reporter:資產掃描報告
生成美術資源分析報告,匯總掃描結果,輔助資源管理與優化。
7.1 工具介紹
-
導入按鈕(Import):可以導入單個報告文件。
-
導入按鈕(Multi-Import):可以同時導入多個報告文件并合并顯示(注意:掃描器必須一致)。
-
導出選擇按鈕(Export Select):導出所有勾選的元素關聯的資源文件(文件拷貝)。
-
修復所有按鈕(Fix All):修復所有未通過元素(排除白名單和隱藏元素)。
-
修復選擇按鈕(Fix Select):修復所有勾選的元素(包含白名單和隱藏元素)。
-
顯示隱藏元素:顯示隱藏元素(眼睛開關控制顯隱)。
-
顯示通過元素:顯示通過元素。
-
顯示白名單元素:顯示白名單元素。
-
注意:該工具僅支持Unity2019.4+
7.2 搜索欄支持
- 通用關鍵字搜索
例如:輸入某個資源的文件名稱,會自動過濾。
- 指定項的關鍵字搜索
例如:搜索“錯誤信息”項的內容,可以輸入以下命令。
注意:中間冒號為小寫。左側為指定項,右側為關鍵字。
錯誤信息:安卓格式不對
- 指定項的數值比較搜索
例如:比較“內存大小”項的數值,可以輸入以下命令。
注意:中間為比較符號。左側為指定項,右側為比較數值。
內存大小=1024
圖片寬度>1024
圖片寬度>=1024
圖片高度<1024
圖片高度<=1024
四、YooAsset資源系統的運行模式
1、編輯器模擬模式 (EditorSimulateMode)
在編輯器下,不需要構建資源包,來模擬運行游戲。直接運行即可。注意該模式只在編輯器下起效
2、單機運行模式 (OfflinePlayMode)
對于不需要熱更新資源的游戲,可以使用單機運行模式。注意該模式需要構建資源包。
打包時,選擇Copy Buildin File Option首包資源文件的拷貝方式
為ClearAndCopyAll(清空后拷貝所有文件)
模式
打包出來的所有文件會復制一份到Assets\StreamingAssets\yoo\DefaultPackage目錄下,當然你也可以手動復制過來
運行效果
3、聯機運行模式 (HostPlayMode)
對于需要熱更新資源的游戲,可以使用聯機運行模式。注意:該模式需要構建資源包。
清空之前復制在流文件夾下的資源
本地電腦模擬服務器環境,我這里使用的是phpstudy。
下載安裝phpstudy:https://old.xp.cn/download.html
把打包好的文件復制放入服務器路徑
這里我放在。。。\CDN\PC\v1.0
, 是因為示例代碼中寫好了這個路徑
配置網站域名,記得開啟nginx服務器
記得打開高級設置里最下面的“目錄索引”,這樣我沒才可以直接訪問服務器目錄
網頁打開 http://localhost/CDN/PC/v1.0/
可以看到資源
把之前打好的version文件和bytes文件復制放回流文件夾。這是提供當前版本號,為了對比
服務器版本號的
修改為聯網運行模式
將游戲打為PC包,記得添加對應的場景
點擊運行,首次運行游戲會提示資源更新。
點擊yes,下載更新補丁。即可開始游玩游戲
我們修改內容,試試熱更效果,比如我在首頁UI面板添加一個按鈕
重新構建資源
復制新構建的資源到服務器..\CDN\PC\v1.0
目錄下
重新運行前面打的PC包,可以看到檢查到資源更新需要下載資源。
點擊yes,下載后可以看到更新后的按鈕,至此完成資源熱更新
4、Web運行模式 (WebPlayMode)
針對WebGL平臺的專屬模式,包括微信小游戲,抖音小游戲都需要選擇該模式。注意:該模式需要構建資源包。
具體請參考官方文檔:小游戲方案
5、自定義運行模式 (CustomPlayMode)
支持多個文件系統。
注意:列表最后一個元素作為主文件系統!
五、YooAsset資源熱更新實踐
1、導入資源
隨便導入一些資源作為熱更新的資源
記得修改圖片類型為Sprite
2、將圖片1進行打包
結果
3、復制version文件和bytes文件到我們的流文件夾
把打好的version文件和bytes文件復制放回流文件夾。這是提供當前版本號,為了對比
服務器版本號的。
4、開啟允許從http下載
修改項目設置,開啟允許從http下載
5、復制前面打包出來的資源到本地資源服務器,啟動本地資源服務器
這里使用phpstudy模擬本地服務器,具體操作可以看前面
6、手寫熱更新流程代碼
其實就是改造了YooAsset官方例子,并且我已經加了詳細的注釋,就不多介紹了。
using System.Collections;
using UnityEngine;
using YooAsset;/// <summary>
/// YooAsset資源系統測試腳本
/// </summary>
public class MyYooAssetTest : MonoBehaviour
{string hostServerIP = "http://127.0.0.1";//服務器地址string appVersion = "v1.0"; //版本號public EPlayMode PlayMode = EPlayMode.HostPlayMode;//資源系統運行模式public string packageName = "DefaultPackage"; //默認包名private ResourcePackage _package = null; //資源包對象public int downloadingMaxNum = 10;//最大下載數量public int filedTryAgain = 3;//失敗重試次數private ResourceDownloaderOperation _downloader;//下載器private UpdatePackageManifestOperation _operationManifest;//更新清單void Awake(){Debug.Log($"資源系統運行模式:{PlayMode}");Application.targetFrameRate = 60;//設置幀率Application.runInBackground = true;//設置后臺運行DontDestroyOnLoad(gameObject);//確保該對象不會在場景切換時銷毀}IEnumerator Start(){//1.初始化YooAsset資源系統YooAssets.Initialize();//2.初始化資源包yield return StartCoroutine(InitPackage());//3.獲取資源版本yield return StartCoroutine(UpdatePackageVersion());//4.獲取文件清單yield return StartCoroutine(UpdateManifest());//5.創建資源下載器CreateDownloader();//5.開始下載資源文件yield return StartCoroutine(BeginDownload());//6.清理未使用的緩存文件ClearFiles();}#region 初始化資源包private IEnumerator InitPackage(){// 獲取或創建資源包對象_package = YooAssets.TryGetPackage(packageName);if (_package == null)_package = YooAssets.CreatePackage(packageName);// 編輯器下的模擬模式InitializationOperation initializationOperation = null;if (PlayMode == EPlayMode.EditorSimulateMode){var buildResult = EditorSimulateModeHelper.SimulateBuild(packageName);var packageRoot = buildResult.PackageRootDirectory;var createParameters = new EditorSimulateModeParameters();createParameters.EditorFileSystemParameters = FileSystemParameters.CreateDefaultEditorFileSystemParameters(packageRoot);initializationOperation = _package.InitializeAsync(createParameters);}// 單機運行模式if (PlayMode == EPlayMode.OfflinePlayMode){var createParameters = new OfflinePlayModeParameters();createParameters.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters();initializationOperation = _package.InitializeAsync(createParameters);}// 聯機運行模式if (PlayMode == EPlayMode.HostPlayMode){//創建遠端服務實例,用于資源請求string defaultHostServer = GetHostServerURL();string fallbackHostServer = GetHostServerURL();IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);// 創建聯機模式參數,并設置內置及緩存文件系統參數HostPlayModeParameters createParameters = new HostPlayModeParameters{//創建內置文件系統參數BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(),//創建緩存系統參數CacheFileSystemParameters = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices)};//執行異步初始化initializationOperation = _package.InitializeAsync(createParameters);}// WebGL運行模式if (PlayMode == EPlayMode.WebPlayMode){
#if UNITY_WEBGL && WEIXINMINIGAME && !UNITY_EDITORvar createParameters = new WebPlayModeParameters();string defaultHostServer = GetHostServerURL();string fallbackHostServer = GetHostServerURL();string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE"; //注意:如果有子目錄,請修改此處!IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);createParameters.WebServerFileSystemParameters = WechatFileSystemCreater.CreateFileSystemParameters(packageRoot, remoteServices);initializationOperation = _package.InitializeAsync(createParameters);
#elsevar createParameters = new WebPlayModeParameters();createParameters.WebServerFileSystemParameters = FileSystemParameters.CreateDefaultWebServerFileSystemParameters();initializationOperation = _package.InitializeAsync(createParameters);
#endif}yield return initializationOperation;// 如果初始化失敗彈出提示界面if (initializationOperation.Status != EOperationStatus.Succeed){Debug.LogWarning($"{initializationOperation.Error}");PatchEventDefine.InitializeFailed.SendEventMessage();}else{Debug.Log("初始化成功-------------------------");}}/// <summary>/// 獲取資源服務器地址/// </summary>private string GetHostServerURL(){#if UNITY_EDITORif (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)return $"{hostServerIP}/CDN/Android/{appVersion}";else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)return $"{hostServerIP}/CDN/IPhone/{appVersion}";else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)return $"{hostServerIP}/CDN/WebGL/{appVersion}";elsereturn $"{hostServerIP}/CDN/PC/{appVersion}";
#elseif (Application.platform == RuntimePlatform.Android)return $"{hostServerIP}/CDN/Android/{appVersion}";else if (Application.platform == RuntimePlatform.IPhonePlayer)return $"{hostServerIP}/CDN/IPhone/{appVersion}";else if (Application.platform == RuntimePlatform.WebGLPlayer)return $"{hostServerIP}/CDN/WebGL/{appVersion}";elsereturn $"{hostServerIP}/CDN/PC/{appVersion}";
#endif}/// <summary>/// 遠端資源地址查詢服務類/// </summary>private class RemoteServices : IRemoteServices{private readonly string _defaultHostServer;private readonly string _fallbackHostServer;public RemoteServices(string defaultHostServer, string fallbackHostServer){_defaultHostServer = defaultHostServer;_fallbackHostServer = fallbackHostServer;}string IRemoteServices.GetRemoteMainURL(string fileName){return $"{_defaultHostServer}/{fileName}";}string IRemoteServices.GetRemoteFallbackURL(string fileName){return $"{_fallbackHostServer}/{fileName}";}}#endregion#region 獲取資源版本private IEnumerator UpdatePackageVersion(){// 發起異步版本請求RequestPackageVersionOperation operation = _package.RequestPackageVersionAsync();yield return operation;// 處理版本請求結果if (operation.Status != EOperationStatus.Succeed){Debug.LogWarning(operation.Error);}else{Debug.Log($"請求的版本: {operation.PackageVersion}");appVersion = operation.PackageVersion;}}#endregion#region 獲取文件清單private IEnumerator UpdateManifest(){_operationManifest = _package.UpdatePackageManifestAsync(appVersion);yield return _operationManifest;// 處理文件清單結果if (_operationManifest.Status != EOperationStatus.Succeed){Debug.LogWarning(_operationManifest.Error);PatchEventDefine.PackageManifestUpdateFailed.SendEventMessage();yield break;}else{Debug.Log("更新資源清單成功-------------------");}}#endregion#region 創建資源下載器void CreateDownloader(){_downloader = _package.CreateResourceDownloader(downloadingMaxNum, filedTryAgain);if (_downloader.TotalDownloadCount == 0){Debug.Log("沒有需要更新的文件");UpdateDone();}else{// 發現新更新文件后,掛起流程系統// 注意:開發者需要在下載前檢測磁盤空間不足int count = _downloader.TotalDownloadCount;long bytes = _downloader.TotalDownloadBytes;Debug.Log($"需要更新{count}個文件, 大小是{bytes / 1024 / 1024}MB");}}#endregion#region 開始下載資源文件private IEnumerator BeginDownload(){_downloader.DownloadErrorCallback = DownloadErrorCallback;// 單個文件下載失敗_downloader.DownloadUpdateCallback = DownloadUpdateCallback;// 下載進度更新_downloader.BeginDownload();//開始下載yield return _downloader;// 檢測下載結果if (_downloader.Status != EOperationStatus.Succeed){Debug.LogWarning(_operationManifest.Error);yield break;}else{Debug.Log("下載成功-------------------");}}// 單個文件下載失敗public static void DownloadErrorCallback(DownloadErrorData errorData){string fileName = errorData.FileName;string errorInfo = errorData.ErrorInfo;Debug.Log($"下載失敗, 文件名: {fileName}, 錯誤信息: {errorInfo}");}// 下載進度更新public static void DownloadUpdateCallback(DownloadUpdateData updateData){int totalDownloadCount = updateData.TotalDownloadCount;int currentDownloadCount = updateData.CurrentDownloadCount;long totalDownloadSizeBytes = updateData.TotalDownloadBytes;long currentDownloadSizeBytes = updateData.CurrentDownloadBytes;Debug.Log($"下載進度: {currentDownloadCount}/{totalDownloadCount}, " +$"{currentDownloadSizeBytes / 1024}KB/{totalDownloadSizeBytes / 1024}KB");}#endregion#region 清理未使用的緩存文件void ClearFiles(){var operationClear = _package.ClearCacheFilesAsync(EFileClearMode.ClearUnusedBundleFiles);// 清理未使用的文件operationClear.Completed += Operation_Completed;// 添加清理完成回調}//文件清理完成private void Operation_Completed(AsyncOperationBase obj){UpdateDone();}#endregion#region 熱更新結束回調private void UpdateDone(){Debug.Log("熱更新結束");//跳轉場景Debug.Log("跳轉場景");//同步加載資源Sprite bg = _package.LoadAssetSync<Sprite>("Assets/Res/Image/1.jpg").AssetObject as Sprite;GameObject go = new GameObject();go.AddComponent<SpriteRenderer>().sprite = bg;}#endregion
}
7、掛載腳本運行游戲,可以看到熱更和加載成功
8、其他加載資源方式
前面我們舉例用的是同步加載資源方式,也可以選擇其他的方式
8.1 使用委托異步加載資源
我們可以修改UpdateDone方法
#region 熱更新結束回調
private void UpdateDone()
{Debug.Log("熱更新結束");//跳轉場景Debug.Log("跳轉場景");// 同步加載資源// Sprite car = _package.LoadAssetSync<Sprite>("Assets/Res/Image/1.jpg")// .AssetObject as Sprite;// GameObject go = new GameObject();// go.AddComponent<SpriteRenderer>().sprite = car;//異步委托資源加載AssetHandle handle = _package.LoadAssetAsync<Sprite>("Assets/Res/Image/1");handle.Completed += Handle_Completed;
}// 異步委托回調
private void Handle_Completed(AssetHandle handle)
{Sprite bg= handle.AssetObject as Sprite;GameObject go = new GameObject();go.AddComponent<SpriteRenderer>().sprite = bg;
}
#endregion
運行結果
8.2 協程加載資源
//熱更新結束協程
IEnumerator UpdateDoneCoroutine()
{// 協程方式加載資源AssetHandle handle = _package.LoadAssetAsync<Sprite>("Assets/Res/Image/1");yield return handle;Sprite bg = handle.AssetObject as Sprite;GameObject go = new GameObject();go.AddComponent<SpriteRenderer>().sprite = bg;
}
8.3 Task加載資源
//熱更新結束
private async void UpdateDone()
{// Task加載資源AssetHandle handle = _package.LoadAssetAsync<Sprite>("Assets/Res/Image/1");await handle.Task;Sprite bg = handle.AssetObject as Sprite;GameObject go = new GameObject();go.AddComponent<SpriteRenderer>().sprite = bg;
}
9、場景加載
新建一個場景Main,隨便寫一個字上去,做區分
配置新增的場景,并重新把AB包
打包好的AB包資源覆蓋之前的服務器資源
修改UpdateDone方法,加載Main場景
#region 熱更新結束回調
private async void UpdateDone()
{string scenePath = "Assets/Res/Scene/Main.unity"; // 場景路徑var sceneMode = UnityEngine.SceneManagement.LoadSceneMode.Single; // 場景模式var physicsMode = UnityEngine.SceneManagement.LocalPhysicsMode.None; // 物理模式bool suspendLoad = false; // 場景加載到90%是否自動掛起SceneHandle handle = _package.LoadSceneAsync(scenePath, sceneMode, physicsMode, suspendLoad); // 加載場景await handle.Task; // 等待場景加載完成Debug.Log("Scene name is " + handle.SceneName); // 輸出場景名稱
}
#endregion
效果,可以看到運行后,資源加載完成了直接跳轉到了Main場景
10、預制體加載和創建
隨便新建一個預制體Cube
修改UpdateDone
private async void UpdateDone()
{//預制體加載和創建AssetHandle handle = _package.LoadAssetAsync<GameObject>("Assets/Res/Prefab/Cube.prefab");await handle.Task;//方式一GameObject go1 = Instantiate(handle.AssetObject as GameObject);Debug.Log("Prefab go1 name:" + go1.name);//方式二GameObject go2 = handle.InstantiateSync();Debug.Log("Prefab go2 name:" + go2.name);
}
重新打AB包放在服務器后,再運行
11、加載圖片子對象切片
需要在2D圖片中設置一個子圖片切片叫1_1
修改UpdateDone
private async void UpdateDone()
{//圖片子對象加載SubAssetsHandle handle = _package.LoadSubAssetsAsync<Sprite>("Assets/Res/Image/1");await handle.Task;var sprite = handle.GetSubAssetObject<Sprite>("1_1");new GameObject().AddComponent<SpriteRenderer>().sprite = sprite;Debug.Log("Sprite name: " + sprite.name);
}
重新打AB包放在服務器后,再運行
12、卸載相關
12.1 回收不再使用的資源
說明:卸載引用計數為零的資源
var operation = package.UnloadUnusedAssetsAsync();
await operation.Task;
12.2 強制回收所有資源
var operation = package.UnloadAllAssetsAsync();
await operation.Task;
12.3 嘗試卸載指定的資源
說明:要未被引用的,否則無效
package.TryUnloadUnusedAsset("Assets/GameRes/Panel/login.prefab");
六、YooAsset資源加密解密
在YooAsset的包中,可以搜到加密解密的示例代碼:加密解密的示例代碼
1、加密資源對象
我們可以修改代碼只對Image目錄下的資源進行加密,加密偏移設置為32。
注意
:BundleStream相關代碼會在后面補充
using System;
using System.IO;
using YooAsset;/// <summary>
/// 文件流加密方式:針對資源文件的二進制數據進行逐字節異或加密
/// </summary>
public class FileStreamEncryption : IEncryptionServices
{/// <summary>/// 對傳入的文件數據進行加密操作/// </summary>/// <param name="fileInfo">包含文件加載路徑和包名等信息</param>/// <returns>返回加密結果,包括是否加密和加密后的數據</returns>public EncryptResult Encrypt(EncryptFileInfo fileInfo){// 只對包名包含 "Image" 字符串的資源進行加密// 注意:包名默認采用的是收集器的父目錄名稱, 并且大寫要轉換為下劃線_if (fileInfo.BundleName.Contains("_image")){// 讀取文件所有字節數據var fileData = File.ReadAllBytes(fileInfo.FileLoadPath);// 對每個字節執行異或運算,異或因子為32,實現簡單加密for (int i = 0; i < fileData.Length; i++){//每個字節與密鑰進行按位異或(XOR)運算。//異或加密的特點:解密時,只需再次異或同一個密鑰即可恢復原始數據。fileData[i] ^= BundleStream.KEY; //KEY是32,BundleStream代碼在后面補充}// 構建加密結果對象,標記為已加密并返回加密后的數據EncryptResult result = new EncryptResult();result.Encrypted = true;result.EncryptedData = fileData;return result;}else{// 如果包名不符合條件,不進行加密,返回未加密的結果EncryptResult result = new EncryptResult();result.Encrypted = false;return result;}}
}/// <summary>
/// 文件偏移加密方式:在原始文件數據前增加一定長度的偏移數據,實現簡單的加密處理
/// </summary>
public class FileOffsetEncryption : IEncryptionServices
{/// <summary>/// 對傳入的文件數據進行加密處理(數據偏移)/// </summary>/// <param name="fileInfo">包含文件加載路徑和包名等信息</param>/// <returns>返回加密結果,包括是否加密和加密后的數據</returns>public EncryptResult Encrypt(EncryptFileInfo fileInfo){// 只對包名包含 "Image" 字符串的資源進行加密// 注意:包名默認采用的是收集器的父目錄名稱, 并且大寫要轉換為下劃線_if (fileInfo.BundleName.Contains("_image")) //判斷資源包是否包含 該字符串{// 設置偏移長度(字節數)int offset = 32;// 讀取原始文件所有字節數據byte[] fileData = File.ReadAllBytes(fileInfo.FileLoadPath);// 創建一個新的字節數組,新數組長度為原數據長度加上偏移長度var encryptedData = new byte[fileData.Length + offset];// 將原始文件數據拷貝到新數組中,目標位置從偏移量開始(前面的偏移部分為空)//拷貝原始數據到加密數組中, 參數 源數據 源數據起始位置, 目標數組, 目標數組的起始位置, 拷貝的字節數//相當于前面空出了32字節, 剩下的全部往后挪 Buffer.BlockCopy(fileData, 0, encryptedData, offset, fileData.Length);// 構建加密結果對象,標記為已加密并返回帶有偏移的新數據EncryptResult result = new EncryptResult();result.Encrypted = true;result.EncryptedData = encryptedData;return result;}else{// 如果包名不符合條件,不進行加密,返回未加密的結果EncryptResult result = new EncryptResult();result.Encrypted = false;return result;}}
}
打包時會多出兩個選項,因為YooAsset會自動檢查繼承IEncryptionServices接口的類。
我們測試使用偏移加密進行打包,也就是選擇FileOffsetEncryption
,并將打包后的資源放在服務器。
2、解密資源對象
同樣是復制TestBundleEncryption中的資源文件解密流BundleStream
using System.IO;/// <summary>
/// 資源文件解密流:通過繼承 FileStream,實現讀取數據時自動對數據進行異或解密處理
/// </summary>
public class BundleStream : FileStream
{// 異或解密的密鑰常量,值為 32public const byte KEY = 32;/// <summary>/// 構造函數:以指定的路徑、文件模式、文件訪問權限和文件共享選項初始化 BundleStream 實例/// </summary>/// <param name="path">文件路徑</param>/// <param name="mode">文件操作模式</param>/// <param name="access">文件訪問權限</param>/// <param name="share">文件共享選項</param>public BundleStream(string path, FileMode mode, FileAccess access, FileShare share): base(path, mode, access, share){}/// <summary>/// 構造函數:以指定的路徑和文件模式初始化 BundleStream 實例,使用默認訪問權限和共享選項/// </summary>/// <param name="path">文件路徑</param>/// <param name="mode">文件操作模式</param>public BundleStream(string path, FileMode mode): base(path, mode){}/// <summary>/// 重寫 Read 方法:讀取指定數量的字節到數組中,并對讀取到的每個字節進行異或解密操作/// </summary>/// <param name="array">存儲讀取數據的字節數組</param>/// <param name="offset">數組中開始寫入數據的偏移位置</param>/// <param name="count">要讀取的最大字節數</param>/// <returns>實際讀取的字節數</returns>public override int Read(byte[] array, int offset, int count){// 調用基類 FileStream 的 Read 方法,將數據讀取到數組中var index = base.Read(array, offset, count);// 對數組中的所有字節進行異或解密操作(還原原始數據)for (int i = 0; i < array.Length; i++){array[i] ^= KEY;}// 返回實際讀取的字節數return index;}
}
以及資源文件流解密類FileStreamDecryption和資源文件偏移解密類。
using System.IO;
using UnityEngine;
using YooAsset;/// <summary>
/// 資源文件流解密類
/// 該類實現了 IDecryptionServices 接口,通過自定義流(BundleStream)對加密的資源包進行解密操作。
/// </summary>
public class FileStreamDecryption : IDecryptionServices
{/// <summary>/// 同步方式加載解密的資源包對象/// 注意:加載的流對象會在資源包對象釋放時自動釋放,無需手動管理流生命周期/// </summary>/// <param name="fileInfo">包含資源包加載路徑、CRC校驗碼等信息</param>/// <returns>返回包含解密流和加載結果的 DecryptResult 對象</returns>DecryptResult IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo){// 創建自定義的 BundleStream 對象,用于解密文件數據BundleStream bundleStream =new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);// 構建解密結果對象DecryptResult decryptResult = new DecryptResult();// 保存解密流,便于后續自動釋放decryptResult.ManagedStream = bundleStream;// 從解密流中同步加載資源包,傳入 CRC 校驗碼和自定義的讀取緩沖區大小decryptResult.Result =AssetBundle.LoadFromStream(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize());return decryptResult;}/// <summary>/// 異步方式加載解密的資源包對象/// 注意:加載的流對象會在資源包對象釋放時自動釋放,無需手動管理流生命周期/// </summary>/// <param name="fileInfo">包含資源包加載路徑、CRC校驗碼等信息</param>/// <returns>返回包含解密流和異步加載請求的 DecryptResult 對象</returns>DecryptResult IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo){// 創建自定義的 BundleStream 對象,用于解密文件數據BundleStream bundleStream =new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);// 構建解密結果對象DecryptResult decryptResult = new DecryptResult();// 保存解密流,便于后續自動釋放decryptResult.ManagedStream = bundleStream;// 從解密流中異步加載資源包,傳入 CRC 校驗碼和自定義的讀取緩沖區大小decryptResult.CreateRequest =AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize());return decryptResult;}/// <summary>/// 獲取解密后的字節數據/// 當前未實現該方法,調用時會拋出 NotImplementedException 異常/// </summary>/// <param name="fileInfo">包含解密文件相關信息</param>/// <returns>解密后的字節數組</returns>byte[] IDecryptionServices.ReadFileData(DecryptFileInfo fileInfo){throw new System.NotImplementedException();}/// <summary>/// 獲取解密后的文本數據/// 當前未實現該方法,調用時會拋出 NotImplementedException 異常/// </summary>/// <param name="fileInfo">包含解密文件相關信息</param>/// <returns>解密后的文本字符串</returns>string IDecryptionServices.ReadFileText(DecryptFileInfo fileInfo){throw new System.NotImplementedException();}/// <summary>/// 獲取用于 AssetBundle 加載時的讀取緩沖區大小/// </summary>/// <returns>緩沖區大小(單位:字節)</returns>private static uint GetManagedReadBufferSize(){return 1024;}
}/// <summary>
/// 資源文件偏移解密類
/// 該類實現了 IDecryptionServices 接口,通過文件偏移的方式加載資源包,無需對流數據進行解密處理
/// </summary>
public class FileOffsetDecryption : IDecryptionServices
{/// <summary>/// 同步方式加載資源包對象/// 注意:該方式直接通過文件路徑加載資源包,加載時會跳過文件開頭的偏移數據/// </summary>/// <param name="fileInfo">包含資源包加載路徑、CRC校驗碼等信息</param>/// <returns>返回包含加載結果的 DecryptResult 對象</returns>DecryptResult IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo){// 構建解密結果對象,ManagedStream 設為 null(無自定義流)DecryptResult decryptResult = new DecryptResult();decryptResult.ManagedStream = null;// 從文件中同步加載資源包,跳過文件偏移部分decryptResult.Result = AssetBundle.LoadFromFile(fileInfo.FileLoadPath, fileInfo.FileLoadCRC, GetFileOffset());return decryptResult;}/// <summary>/// 異步方式加載資源包對象/// 注意:該方式直接通過文件路徑加載資源包,加載時會跳過文件開頭的偏移數據/// </summary>/// <param name="fileInfo">包含資源包加載路徑、CRC校驗碼等信息</param>/// <returns>返回包含異步加載請求的 DecryptResult 對象</returns>DecryptResult IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo){// 構建解密結果對象,ManagedStream 設為 null(無自定義流)DecryptResult decryptResult = new DecryptResult();decryptResult.ManagedStream = null;// 從文件中異步加載資源包,跳過文件偏移部分decryptResult.CreateRequest =AssetBundle.LoadFromFileAsync(fileInfo.FileLoadPath, fileInfo.FileLoadCRC, GetFileOffset());return decryptResult;}/// <summary>/// 獲取解密后的字節數據/// 當前未實現該方法,調用時會拋出 NotImplementedException 異常/// </summary>/// <param name="fileInfo">包含解密文件相關信息</param>/// <returns>解密后的字節數組</returns>byte[] IDecryptionServices.ReadFileData(DecryptFileInfo fileInfo){throw new System.NotImplementedException();}/// <summary>/// 獲取解密后的文本數據/// 當前未實現該方法,調用時會拋出 NotImplementedException 異常/// </summary>/// <param name="fileInfo">包含解密文件相關信息</param>/// <returns>解密后的文本字符串</returns>string IDecryptionServices.ReadFileText(DecryptFileInfo fileInfo){throw new System.NotImplementedException();}/// <summary>/// 獲取文件偏移量,表示資源包文件開頭需要跳過的字節數/// </summary>/// <returns>偏移字節數</returns>private static ulong GetFileOffset(){return 32;}
}
3、使用解密對象解密加密的資源
在MyYooAssetTest,創建聯機模式參數,并設置內置及緩存文件系統參數時傳入偏移解密對象FileOffsetDecryption
// 創建聯機模式參數,并設置內置及緩存文件系統參數
HostPlayModeParameters createParameters = new HostPlayModeParameters
{//創建內置文件系統參數BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(),//創建緩存系統參數CacheFileSystemParameters = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices,new FileOffsetDecryption())
};
其他還是用之前實踐的代碼
運行效果
如果改了偏移量,比如前面加密用的32,這里解密我們改成64。加密解密的秘鑰對不上,則會加載失敗。
/// <summary>
/// 獲取文件偏移量,表示資源包文件開頭需要跳過的字節數
/// </summary>
/// <returns>偏移字節數</returns>
private static ulong GetFileOffset()
{return 64;
}
運行效果
專欄推薦
地址 |
---|
【unity游戲開發入門到精通——C#篇】 |
【unity游戲開發入門到精通——unity通用篇】 |
【unity游戲開發入門到精通——unity3D篇】 |
【unity游戲開發入門到精通——unity2D篇】 |
【unity實戰】 |
【制作100個Unity游戲】 |
【推薦100個unity插件】 |
【實現100個unity特效】 |
【unity框架/工具集開發】 |
【unity游戲開發——模型篇】 |
【unity游戲開發——InputSystem】 |
【unity游戲開發——Animator動畫】 |
【unity游戲開發——UGUI】 |
【unity游戲開發——聯網篇】 |
【unity游戲開發——優化篇】 |
【unity游戲開發——shader篇】 |
【unity游戲開發——編輯器擴展】 |
【unity游戲開發——熱更新】 |
完結
好了,我是向宇
,博客地址:https://xiangyu.blog.csdn.net,如果學習過程中遇到任何問題,也歡迎你評論私信找我。
贈人玫瑰,手有余香!如果文章內容對你有所幫助,請不要吝嗇你的點贊評論和關注
,你的每一次支持
都是我不斷創作的最大動力。當然如果你發現了文章中存在錯誤
或者有更好的解決方法
,也歡迎評論私信告訴我哦!