【unity游戲開發——熱更新】YooAsset簡化資源加載、打包、更新等流程

注意:考慮到熱更新的內容比較多,我將熱更新的內容分開,并全部整合放在【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,如果學習過程中遇到任何問題,也歡迎你評論私信找我。

贈人玫瑰,手有余香!如果文章內容對你有所幫助,請不要吝嗇你的點贊評論和關注,你的每一次支持都是我不斷創作的最大動力。當然如果你發現了文章中存在錯誤或者有更好的解決方法,也歡迎評論私信告訴我哦!
在這里插入圖片描述

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

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

相關文章

AWS RDS/Aurora 開啟 Database Insights 高級模式全攻略

想要深入了解數據庫性能問題?AWS Database Insights 高級模式為您提供強大的性能分析工具。本文詳細對比標準模式與高級模式的功能差異,并提供完整的啟用指南和實戰測試結果。 一、Database Insights 模式對比 AWS CloudWatch Database Insights 提供兩種模式:標準模式和高…

XML SimpleXML

XML SimpleXML 引言 XML&#xff08;可擴展標記語言&#xff09;是一種用于存儲和傳輸數據的標記語言&#xff0c;它被廣泛應用于Web服務和數據交換。SimpleXML是PHP中一個處理XML數據非常便捷的庫。本文將詳細介紹SimpleXML庫的基本用法&#xff0c;幫助讀者快速掌握XML數據…

Docker簡單介紹與使用以及下載對應鏡像(項目前置)

DockerDocker安裝Docker卸載Docker配置鏡像源配置鏡像加速 Docker服務命令1.鏡像操作命令2.容器操作命令 安裝Mysql**數據卷掛載** Docker 在linux中軟件安裝說起: 以前在linux中安裝軟件,是直接安裝在linux操作系統中,軟件和操作系統耦合度很高,不方便管理. 因為linux版本不…

MyBatis 簡介

MyBatis 簡介 MyBatis 是一款優秀的持久層框架&#xff0c;它支持定制化 SQL、存儲過程以及高級映射&#xff0c;能夠幫助開發者將 Java 對象與數據庫表進行靈活映射&#xff0c;簡化數據持久化操作。以下從多個維度詳細介紹 MyBatis&#xff1a; 一、核心定位與優勢 輕量級…

自監督學習在合成孔徑聲吶目標識別中的應用之論文閱讀

自監督學習在合成孔徑聲吶目標識別中的應用 BW Sheffield 美國巴拿馬城海軍水面作戰中心 1 引言 在自主水下航行器(AUVs)中應用計算機視覺面臨著獨特的挑戰,因為海洋環境往往條件不可預測且極為嚴苛。傳統計算機視覺研究主要依賴光學相機成像,而在光照不足、懸浮沉積物及水…

進程間通信2(命名管道)linux

1 命名管道 前面講到匿名管道&#xff0c;有一個很大的限制&#xff0c;那就是只有具有相同祖先&#xff08;具有親緣關系&#xff09;的進程間才能進行通信&#xff0c;但是如果想實現不同進程間的通信&#xff0c;這個時候命名管道就發揮著巨大作用。 命名管道是一種特殊類…

簡單通過SenseVoice給自己配置一個語音轉文字服務

首先把代碼下載下來 gitgithub.com:FunAudioLLM/SenseVoice.git 然后寫一個docker文件 FROM ubuntu:latestRUN apt-get update -y RUN apt-get install -y python3-full python3-pip RUN mkdir -p /SenseVoice WORKDIR /SenseVoice RUN python3 -m venv . ENV USE_CUDA0 EXP…

網絡釣魚攻擊

?根據2023年Proofpoint年度網絡釣魚報告顯示&#xff1a;91%的針對性攻擊始于釣魚郵件&#xff0c;平均每30秒就有一個企業成為攻擊目標&#xff0c;全球損失超過$6.5B? 一、釣魚攻擊技術深度解析 1. 釣魚攻擊核心技術架構 2. 現代釣魚技術演進 ?攻擊向量升級路線? ?當前…

uvicorn api:app --host 0.0.0.0 --port 7777容器運行失敗

docker logs pycorrector-container-gpu 你這個報錯的核心是&#xff1a; ERROR: Error loading ASGI app, Could not import module "api".這說明&#xff1a; uvicorn api:app 沒有找到 api.py 文件&#xff0c;或者沒法導入 app 對象。 &#x1f50d; 一步步排查…

熱成像儀測MOSFET溫度

熱成像儀測MOSFET溫度 根據提供的搜索結果&#xff0c;熱測量方法主要分為非接觸式和接觸式兩大類&#xff0c;針對不同材料特性和測量場景各有優勢。以下是核心方法的總結及關鍵技術要點&#xff1a; &#x1f525; 一、非接觸式熱測量方法 紅外熱成像技術 原理&#xff1a;通…

Dagster資產元數據與標簽:數據治理的利器

在現代數據棧中&#xff0c;有效的數據治理至關重要。Dagster作為領先的數據編排平臺&#xff0c;提供了強大的資產元數據和標簽功能&#xff0c;幫助團隊更好地理解、組織和跟蹤數據資產。本文將深入探討Dagster中的資產元數據和標簽功能&#xff0c;展示如何利用這些功能提升…

基于物聯網的智能飲水機系統設計

標題:基于物聯網的智能飲水機系統設計 內容:1.摘要 隨著物聯網技術的快速發展&#xff0c;智能設備在日常生活中的應用越來越廣泛。本研究的目的是設計一種基于物聯網的智能飲水機系統&#xff0c;以提高飲水機的使用便捷性和智能化程度。方法上&#xff0c;通過傳感器實時監測…

DP讀書:NEC年終小結和顯示器【明基rd28u】

一點真實體驗_寫在ROBOCON2025國賽前 很久沒有寫這種關于感受的博客了&#xff0c;就用真實感受的角度來看看一次眾測的經歷&#xff0c;哈哈^ 差不多一個月前&#xff0c;我收到了明基的28寸顯示器&#xff0c;體驗了差不多2周左右&#xff0c;一直把顯示器掛在實驗室倉庫La…

Solana 一鍵冷分倉機制詳解:如何用技術手段構建健康的持倉結構

在 Solana 的快速發幣環境中&#xff0c;許多項目方在成功部署代幣后&#xff0c;會面臨一個共通問題——如何避免持倉結構過于集中。無論是初始鑄造的 Token、流動性預留份額&#xff0c;還是空投分發的準備金&#xff0c;如果長時間停留在單一錢包地址中&#xff0c;將在鏈上…

【智能體】dify部署本地步驟

從git克隆倉庫到本地 git clone https://github.com/langgenius/dify.git設置環境變量 cd dify cd docker cp .env.example .envdocker啟動 docker compose up -d在瀏覽器打開網址 http://localhost/install 登錄后即可使用

開源鴻蒙6.0 Beta1版本發布!深圳觸覺智能即將適配RK3566/RK3568/RK3576/RK3588等芯片

開放原子開源鴻蒙&#xff08;OpenAtom OpenHarmony&#xff0c;簡稱“開源鴻蒙”或“OpenHarmony”&#xff09;6.0 Beta1版本正式發布。相比5.1.0 Release版本進一步增強ArkUI組件能力&#xff0c;提供更安全、更靈活的組件布局&#xff1b;增強分布式數據管理能力&#xff0…

機器學習 (ML) 基礎入門指南

一、機器學習概述 &#xff08;一&#xff09;定義 在當今科技飛速發展的時代&#xff0c;機器學習作為人工智能的一個重要分支&#xff0c;正深刻地改變著我們的生活和工作方式。根據機器學習泰斗、卡耐基梅隆大學的湯姆米切爾 (Tom Mitchell) 教授的定義&#xff0c;機器學…

基于ARM ubuntu如何進行交叉編譯

場景總結&#xff1a; 平臺&#xff1a;x86 主機 工具鏈&#xff1a;aarch64-linux-gnu-gcc&#xff08;用于編譯 64-bit ARM 程序&#xff09; 目標&#xff1a;讓 gcc 自動使用 ARM Ubuntu rootfs 中的頭文件和庫&#xff08;位于 /opt/arm64-ubuntu&#xff09; 不希望每…

java+vue+SpringBoo社區藥房系統(程序+數據庫+報告+部署教程+答辯指導)

源代碼數據庫LW文檔&#xff08;1萬字以上&#xff09;開題報告答辯稿ppt部署教程代碼講解代碼時間修改工具 技術實現 開發語言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot數據庫&#xff1a;mysql 開發工具 JDK版本&#xff1a;JDK1.…

VS2022打Unity中的腳本斷點時出現當前不會命中斷點,找不到相應位置

今天遇到一個很傻的問題&#xff0c; 在新電腦中安裝了Unity和VS2022后&#xff0c;在Unity中打開一個新腳本&#xff0c;打斷點時報警告&#xff0c;如下&#xff1a; 原來在Unity中新建的腳本&#xff0c;如果沒有被使用&#xff0c;就會出現找不到位置的錯誤&#xff01; 反…