天天看點

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

資源下載下傳流程圖

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

流程跳轉的日志

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

版本資訊-版本檢測-下載下傳版本清單-下載下傳散檔案代碼分析

  1. 進入ProcedureCheckVersion.OnEnter流程,進行task請求,userData為StarForce.ProcedureCheckVersion

    建立WebRequest網絡請求任務調用堆棧為

初始化任務:UnityGameFramework.Runtime.WWWFormInfo
GameFramework.TaskBase:Initialize (int,string,int,object) GameFramework.WebRequest.WebRequestManager/WebRequestTask:Create (string,byte[],string,int,single,object)
GameFramework.WebRequest.WebRequestManager:AddWebRequest (string,byte[],string,int,object)
UnityGameFramework.Runtime.WebRequestComponent:AddWebRequest (string,byte[],UnityEngine.WWWForm,string,int,object) 
UnityGameFramework.Runtime.WebRequestComponent:AddWebRequest (string,object) 
StarForce.ProcedureCheckVersion:OnEnter (GameFramework.Fsm.IFsm`1<GameFramework.Procedure.IProcedureManager>)      
  1. 請求成功,讀取伺服器中Version.txt檔案,Version.txt檔案内容為
{
  "ForceUpdateGame": false,
  "LatestGameVersion": "0.1.0",
  "InternalGameVersion": 0,
  "InternalResourceVersion": 2,
  "UpdatePrefixUri": "http://10.12.24.82:10089/Windows",
  "VersionListLength": 7160,
  "VersionListHashCode": 1835127216,
  "VersionListCompressedLength": 2649,
  "VersionListCompressedHashCode": -1660134522
}      
  1. 如果不需要強行更新版本,下載下傳版本資訊檔案GameFrameworkVersion.6d61d1b0.dat

    調用堆棧

增加下載下傳任務:儲存位址:C:/Users/luoyikun_l/AppData/LocalLow/Game Framework/Star Force/GameFrameworkVersion.dat源位址:http://10.12.24.82:10089/Windows/GameFrameworkVersion.6d61d1b0.dat
GameFramework.Download.DownloadManager:AddDownload (string,string,string,int,object) 
GameFramework.Download.DownloadManager:AddDownload (string,string,object) 
GameFramework.Resource.ResourceManager/VersionListProcessor:UpdateVersionList (int,int,int,int)
GameFramework.Resource.ResourceManager:UpdateVersionList (int,int,int,int,GameFramework.Resource.UpdateVersionListCallbacks) 
UnityGameFramework.Runtime.ResourceComponent:UpdateVersionList (int,int,int,int,GameFramework.Resource.UpdateVersionListCallbacks)
StarForce.ProcedureUpdateVersion:OnEnter (GameFramework.Fsm.IFsm`1<GameFramework.Procedure.IProcedureManager>)      
  1. VersionListProcessor中OnDownloadSuccess,監聽的是DownloadMananger下載下傳成功通知,用來檢驗GameFrameworkVersion.dat(版本檔案list資訊集合)是否按照Version.txt 裡資訊下載下傳成功
  2. ProcedureCheckResources:資源檢查流程,用來确定待下載下傳的清單

    ResourceChecker,進入到檔案檢查階段,有多少檔案需要下載下傳

    核心函數

    //得到各個檔案的狀态,移除,移動,更新。可以得到差異更新總量

    private void RefreshCheckInfoStatus()

    調用堆棧

Check resources complete, '18' resources need to update, compressed length is '11438117', uncompressed length is '12336939'.
StarForce.ProcedureCheckResources:OnCheckResourcesComplete (int,int,int,long,long) 
GameFramework.Resource.ResourceManager:OnCheckerResourceCheckComplete (int,int,int,long,long) 
GameFramework.Resource.ResourceManager/ResourceChecker:RefreshCheckInfoStatus () 
GameFramework.Resource.ResourceManager/ResourceChecker:OnLoadUpdatableVersionListSuccess (string,byte[],single,object)      
  1. ProcedureUpdateResources資源更新流程,下載下傳資源,并建立檔案系統

    檔案系統支援差異更新,例如上次要下18個,中斷後再下載下傳6個

    Check resources complete, ‘6’ resources need to update, compressed length is ‘130607’, uncompressed length is ‘192052’.

    使用ResourceUpdater進行下載下傳,update中輪詢,把所有下載下傳任務,依次塞入空閑代理下載下傳,同時可以3個下載下傳

類說明

ResourceUpdater

update中輪詢與TaskPool結合

public void Update(float elapseSeconds, float realElapseSeconds)
            {
               if (m_UpdateWaitingInfo.Count > 0)
                {
                    int freeCount = m_DownloadManager.FreeAgentCount - m_DownloadManager.WaitingTaskCount;
                    if (freeCount > 0)
                    {
                        for (int i = 0, count = 0; i < m_UpdateWaitingInfo.Count && count < freeCount; i++)
                        {
                            if (DownloadResource(m_UpdateWaitingInfo[i]))
                            {
                                count++;
                            }
                        }
                    }

                    return;
                }
            }      
GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

每下載下傳完一個,m_UpdateCandidateInfo-1,m_UpdateCandidateInfo.Count <= 0,候選下載下傳全部完成,更新完畢

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

DownloadManager

建立任務池,并增加任務代理

m_TaskPool = new TaskPool<DownloadTask>();
DownloadAgent agent = new DownloadAgent(downloadAgentHelper);
            agent.DownloadAgentStart += OnDownloadAgentStart;
            agent.DownloadAgentUpdate += OnDownloadAgentUpdate;
            agent.DownloadAgentSuccess += OnDownloadAgentSuccess;
            agent.DownloadAgentFailure += OnDownloadAgentFailure;

            m_TaskPool.AddAgent(agent);      

在DownloadComponent start 建立m_DownloadAgentHelperCount (目前為3)個任務代理,代表能同時下載下傳的代理數

具體下載下傳代理是DownloadAgent決定

DownloadAgent又由DownloadAgentHelperBase 下載下傳代理輔助器決定使用哪種下載下傳方式

gf中内置了UnityWebRequest實作的下載下傳代理輔助器。

UnityWebRequestDownloadAgentHelper

真正的下載下傳器,可以替換成任意下載下傳api

使用 UnityWebRequest 實作的下載下傳代理輔助器,針對的是單個下載下傳

update判斷 m_UnityWebRequest.isDone,如果有網絡錯誤立馬抛出事件

DownloadAgent

下載下傳完成,OnDownloadAgentHelperComplete

下載下傳代理器成功了,把臨時檔案.download 變為正式檔案,可用于斷點續傳

并且發送通知:ResourceManager.OnDownloadSuccess

VersionListProcessor

//版本資源清單處理器。

建立時,監聽DownloadManager.DownloadSuccess

執行OnDownloadSuccess

下載下傳成功了

  1. 下載下傳的壓縮長度一緻
  2. crc32碼一緻
  3. 進行解壓操作,且解壓正常(預設是GZip解壓)
  4. 解壓後的大小與伺服器檔案描述一緻
  5. 寫入解壓後的檔案
  6. 通知版本list檔案更新成功

    下載下傳失敗,删除檔案

    全部校驗成功,關閉并清理版本資源清單處理器。

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

TaskPool

TaskPool是任務池,使用連結清單與棧來維護任務與任務代理,并提供任務的添加與移除等操作。WebRequest(網絡請求), Download(下載下傳), LoadResource(加載資源)時使用。

ITask是任務接口,主要存儲任務執行時所需的資料

ITaskAgent是任務代理接口,負責對任務進行處理(實際的處理邏輯則通過調用具體子產品的代理輔助器執行,這一點在後面編寫需要使用任務功能的子產品時會涉及到)

TaskPool中成員

private readonly Stack<ITaskAgent<T>> m_FreeAgents;  //通過棧維護所有空閑代理, 這個代理就是任務的具體實作過程,在架構中很多地方都使用了這種接口方式,具有高度的擴充性。
        private readonly GameFrameworkLinkedList<ITaskAgent<T>> m_WorkingAgents;//通過一個連結清單維護所有的工作代理
        private readonly GameFrameworkLinkedList<T> m_WaitingTasks;//通過一個連結清單維護所有的等待任務      

更新流程詳解

1.資源清單的校驗

應用每一次啟動,首先需要你先得到目前資源總表的内部版本号(内部版本号在ResourceBuilder面闆設定。至于内部版本号的動态擷取過程,采用何種方式,則需要自己來實作,例如讀unity的版本設定),然後即可使用這個最新的内部版本号,調用

CheckVersionListResult ResourceComponent.CheckVersionList(int latestInternalResourceVersion)      

來判定目前的資源總表是不是最新的,此時 CheckVersionList 方法會通路讀寫目錄,并嘗試讀取 GameFrameworkVersion.dat 檔案,如果檔案沒有或者内部攜帶的資源内部版本号與伺服器中version.txt 不同,則會傳回資源需要更新的枚舉值,否則則會傳回不需要更新。

伺服器中遠端版本資訊version.txt 内容為

{
  "ForceUpdateGame": false,
  "LatestGameVersion": "0.1.0",
  "InternalGameVersion": 0,
  "InternalResourceVersion": 2,
  "UpdatePrefixUri": "http://10.12.24.82:10089/Windows",
  "VersionListLength": 7138,
  "VersionListHashCode": -1969978894,
  "VersionListCompressedLength": 2653,
  "VersionListCompressedHashCode": 861209557
}      

項目中Builtin Data資訊BuildInfo.txt,隻會決定擷取遠端version.txt的路徑,遊戲app版本号是代碼擷取,res版本号是按照本地可讀寫目錄GameFrameworkVersion.dat檔案是否存在

BuildInfo.txt檔案内容

{
  "GameVersion": "0.1.0",
  "InternalGameVersion": 0,
  "CheckVersionUrl": "http://10.12.24.82:10089/{0}/Version.txt",
  "WindowsAppUrl": "https://starforce.gameframework.cn",
  "MacOSAppUrl": "https://starforce.gameframework.cn",
  "IOSAppUrl": "https://starforce.gameframework.cn",
  "AndroidAppUrl": "https://starforce.gameframework.cn",
  "END_OF_JSON": ""
}      

2.資源清單的更新

如果資源清單需要更新,則此時需要配置好你的更新位址,即公布在網絡上用于下載下傳Full 目錄中檔案的位址。

string ResourceComponent.UpdatePrefixUri      

然後調用更新方法

void ResourceComponent.UpdateVersionList(int versionListLength, int versionListHashCode, int versionListZipLength, int versionListZipHashCode, UpdateVersionListCallbacks updateVersionListCallbacks)      

前四個參數分别為

versionListLength 資源總表檔案長度

versionListHashCode 資源總表檔案校驗和

versionListZipLength 資源總表檔案壓縮後的zip檔案長度

versionListZipHashCode 資源總表檔案壓縮後的zip檔案校驗和

這些參數在 “生成目錄/BuildReport/BuildLog.txt” 檔案的資訊中可以檢視.

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

出現負數不影響使用,為crc32碼轉為int出現的負數

3.資源校驗

首先資源清單檔案事實上一共有三份,除了總表 GameFrameworkVersion.XXXX.dat 和 隻讀目錄下的 GameFreamworkList.dat 之外, 讀寫目錄下也有一份 GameFreamworkList.dat 資源清單檔案,這份檔案記錄的是最後一次更新完畢後讀寫目錄中的資源檔案資訊(如果你的應用程式是第一次啟動,且沒有更新過資源,那麼這一份檔案也是不存在的,但是如果你成功的更新過資源,則由GF架構自動為你生成 )

現在先設定一下資源子產品目前的變體,因為校驗資源這一步即校驗資源檔案是否要更新,同時也會建立資源資訊資料庫用于之後的加載操作,是以在你校驗資源資訊之前務必設定好目前要使用的資源變體,之後如果調用加載資源方法會在此時建立的資源資訊資料庫中尋找資源資訊。除目前變體之外的其他變體的資源資訊将不會在資源資料庫中,如果加載的是其他變體的資源檔案,則被作為無此資源資訊的情況處理。這裡調用

void ResourceComponent.SetCurrentVariant(string currentVariant)

則可以設定變體,預設情況下為“”,也就是無變體。接着就可以正式調用

void ResourceComponent.CheckResources(CheckResourcesCompleteCallback checkResourcesCompleteCallback)

m_ResourceChecker.CheckResources(m_CurrentVariant, ignoreOtherVariant);

開始校驗資源,CheckResources 會以分别讀取三個資源清單檔案進行比較,

如果隻讀目錄或者讀寫目錄下的 GameFreamworkList.dat 檔案不存在,則以該目錄下沒有資源檔案處理。

GameFramework.Resource.ResourceManager.ResourceChecker.CheckResources

//讀寫中GameFrameworkVersion.dat
                m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadWritePath, RemoteVersionListFileName)), new LoadBytesCallbacks(OnLoadUpdatableVersionListSuccess, OnLoadUpdatableVersionListFailure), null);
                //隻讀中GameFrameworkList.dat,為pack資源,随app釋出的
                m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadOnlyPath, LocalVersionListFileName)), new LoadBytesCallbacks(OnLoadReadOnlyVersionListSuccess, OnLoadReadOnlyVersionListFailure), null);
                //讀寫中"GameFrameworkList.dat",為每次更新完後更新目前目錄的資源
                m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadWritePath, LocalVersionListFileName)), new LoadBytesCallbacks(OnLoadReadWriteVersionListSuccess, OnLoadReadWriteVersionListFailure), null);      

讀取完三個資源清單檔案内容後,将會以總表中的資源資訊為準,通過總表中記錄的資源資訊的檔案hashcode值作為唯一辨別。

如果某個資源資訊在 兩個GameFreamworkList.dat 資源表都沒有記錄,則将這個資源資訊對應的資源檔案作為需要更新的資源檔案處理,記錄在等待更新清單中。

除此之外,如果發現總表中記錄的資源資訊,在隻讀目錄和讀寫目錄下的 GameFreamworkList.dat 資源表中都存在,則會删除在讀寫目錄中的對應資源檔案已節省空間(因為隻讀目錄中已經有了一份資源檔案,不需要存儲兩份)。

讀取三個檔案後做的處理

CheckResources.RefreshCheckInfoStatus()

在建立完更新清單和資源資訊資料庫之後,接下來就可以進行資源檔案更新了。

GameFramework:資源熱更代碼分析,檢查版本資訊,下載下傳版本檔案,校驗版本檔案,得到更新檔案數量,下載下傳檔案,TaskPool

4.資源更新

資源更新子產品會自動根據我們上一步校驗資源時建立的資源檔案更新清單,前往之前設定的下載下傳位址,依次的下載下傳資源檔案到讀寫目錄中,并在下載下傳完畢後,自動生成讀寫目錄中的 GameFreamworkList.dat 資源表檔案,這個檔案記錄了讀寫目錄至本次更新結束完畢後,讀寫目錄下的資源檔案資訊。友善下一次的更新操作。調用

void UpdateResources(UpdateResourcesCompleteCallback updateResourcesCompleteCallback)

即可開啟更新流程,這個流程很簡單就是下載下傳檔案,然後生成讀寫目錄下的資源清單檔案

GameFrameworkVersion.dat 裡面具體内容

UpdatableVersionList序列化而來

{
  "IsValid": true,
  "ApplicableGameVersion": "0.1.0",
  "InternalResourceVersion": 5,
  "m_IsValid": true,
  "m_ApplicableGameVersion": "0.1.0",
  "m_InternalResourceVersion": 5,
  "m_Assets": [{
    "Name": "Assets/GameMain/UI/UISprites/Common/info.png",
    "m_Name": "Assets/GameMain/UI/UISprites/Common/info.png",
    "m_DependencyAssetIndexes": []
  }, {
    "Name": "Assets/GameMain/UI/UIForms/DialogForm.prefab",
    "m_Name": "Assets/GameMain/UI/UIForms/DialogForm.prefab",
    "m_DependencyAssetIndexes": [7, 91, 92, 109]
  }, {
.....
"m_Resources": [{
    "Name": "Configs",
    "Variant": null,
    "Extension": "dat",
    "LoadType": 0,
    "Length": 1343,
    "HashCode": -456997092,
    "CompressedLength": 1129,
    "CompressedHashCode": 1676554304,
    "m_Name": "Configs",
    "m_Variant": null,
    "m_Extension": "dat",
    "m_LoadType": 0,
    "m_Length": 1343,
    "m_HashCode": -456997092,
    "m_CompressedLength": 1129,
    "m_CompressedHashCode": 1676554304,
    "m_AssetIndexes": [38, 66]
  },

  "m_FileSystems": [],
  "m_ResourceGroups": [{
    "Name": "Base",
    "m_Name": "Base",
    "m_ResourceIndexes": [0, 1, 3, 4, 5, 6, 7]
  }, {
    "Name": "Music",
    "m_Name": "Music",
    "m_ResourceIndexes": [10, 11, 12]
  }]      

GameFrameworkList.dat裡面具體内容

LocalVersionList序列化而來

比上面了缺少asset資訊

{
  "IsValid": true,
  "m_IsValid": true,
  "m_Resources": [{
    "Name": "Configs",
    "Variant": null,
    "Extension": "dat",
    "LoadType": 0,
    "Length": 1343,
    "HashCode": -456997092,
    "m_Name": "Configs",
    "m_Variant": null,
    "m_Extension": "dat",
    "m_LoadType": 0,
    "m_Length": 1343,
    "m_HashCode": -456997092
  }, {      

繼續閱讀