GameFramework: resource hot update code analysis, check version information, download version files, verify version files, get the number of updated files, download files, TaskPool

Resource download flow chart

insert image description here

Process jump log

insert image description here

Version information-version detection-download version list-download bulk file code analysis

  1. Enter the ProcedureCheckVersion.OnEnter process, make a task request, userData
    creates a WebRequest network request task call stack for StarForce.ProcedureCheckVersion
初始化任务: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. The request is successful, and the Version.txt file in the server is read. The content of the Version.txt file is
{
    
    
	"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. If you don’t need to forcefully update the version, download the version information file GameFrameworkVersion.6d61d1b0.dat
    call stack
增加下载任务:保存地址: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. OnDownloadSuccess in VersionListProcessor listens to the DownloadManager download success notification, which is used to check whether the GameFrameworkVersion.dat (version file list information collection) is successfully downloaded according to the information in Version.txt
  2. ProcedureCheckResources: Resource checking process, used to determine the list to be downloaded
    ResourceChecker, enter the file checking stage, how many files need to be downloaded
    Core function
    //get the status of each file, remove, move, update. You can get the total amount of difference update
    private void RefreshCheckInfoStatus()
    call stack
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 resource update process, download resources, and create a file system The file
    system supports differential updates, for example, 18 were downloaded last time, and 6 are downloaded after the interruption.
    Check resources complete, '6' resources need to update, compressed length is '130607' , uncompressed length is '192052'.
    Use ResourceUpdater to download, poll in update, put all download tasks into idle agent download in turn, and 3 downloads at the same time
    insert image description here

class description

ResourceUpdater

Combination of polling and TaskPool in update

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;
                }
            }

insert image description here

Each time one is downloaded, m_UpdateCandidateInfo-1, m_UpdateCandidateInfo.Count <= 0, all candidate downloads are completed, and the update is complete
insert image description here

DownloadManager

Create a task pool and add task agents

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);

Create m_DownloadAgentHelperCount (currently 3) task agents in DownloadComponent start, representing the number of agents that can be downloaded at the
same
time
Auxiliary.
UnityWebRequestDownloadAgentHelper
is a real downloader, which can be replaced by any download api
using UnityWebRequest to implement the download agent helper. It is aimed at
judging m_UnityWebRequest.isDone for a single download update. If there is a network error, an event will be thrown immediately.

DownloadAgent

When the download is complete, the OnDownloadAgentHelperComplete
download agent is successful, and the temporary file .download is changed into an official file, which can be used for resuming uploads
and sending a notification: ResourceManager.OnDownloadSuccess

VersionListProcessor

//Version resource list handler.
When creating, listen to DownloadManager.DownloadSuccess
and execute OnDownloadSuccess
to download successfully

  1. The downloaded compressed length is the same
  2. The crc32 code is consistent
  3. Perform the decompression operation, and the decompression is normal (the default is GZip decompression)
  4. The decompressed size is consistent with the server file description
  5. Write the decompressed file
  6. Notify that the version list file is updated successfully
    . The download fails, delete the file
    , and all verification succeeds. Close and clean up the version resource list processor.

insert image description here

TaskPool

TaskPool is a task pool that uses linked lists and stacks to maintain tasks and task agents, and provides operations such as adding and removing tasks. Used for WebRequest (network request), Download (download), LoadResource (load resource).

ITask is a task interface, which mainly stores the data required for task execution

ITaskAgent is the task agent interface, which is responsible for processing tasks (the actual processing logic is executed by calling the agent assistant of the specific module, which will be involved in writing modules that need to use task functions later)

Members of TaskPool

 private readonly Stack<ITaskAgent<T>> m_FreeAgents;  //通过栈维护所有空闲代理, 这个代理就是任务的具体实现过程,在框架中很多地方都使用了这种接口方式,具有高度的扩展性。
        private readonly GameFrameworkLinkedList<ITaskAgent<T>> m_WorkingAgents;//通过一个链表维护所有的工作代理
        private readonly GameFrameworkLinkedList<T> m_WaitingTasks;//通过一个链表维护所有的等待任务

Detailed update process

1. Verification of the resource list

Every time the application starts, you first need to get the internal version number of the current resource table (the internal version number is set in the ResourceBuilder panel. As for the dynamic acquisition process of the internal version number, you need to implement it yourself, for example, reading unity version setting), then to use this latest build number, call

CheckVersionListResult ResourceComponent.CheckVersionList(int latestInternalResourceVersion) 

To determine whether the current resource table is up-to-date, the CheckVersionList method will access the read-write directory and try to read the GameFrameworkVersion.dat file. If the file does not exist or the internal version number of the resource carried inside is different from the version.txt in the server, It will return the enumeration value that the resource needs to be updated, otherwise it will return that it does not need to be updated.
The content of the remote version information version.txt in the server is

{
    
    
	"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
}

The Builtin Data information BuildInfo.txt in the project will only determine the path to obtain the remote version.txt. The game app version number is obtained by code, and the res version number is based on whether the GameFrameworkVersion.dat file in the local readable and writable directory exists. BuildInfo.txt file
content

{
    
    
  "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. Update of resource list

If the resource list needs to be updated, you need to configure your update address at this time, that is, the address published on the Internet for downloading files in the Full directory.

string ResourceComponent.UpdatePrefixUri

then call the update method

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

The first four parameters are
versionListLength, the file length of the resource table,
versionListHashCode, the checksum of the resource table file,
versionListZipLength, the compressed zip file length of the resource table file,
versionListZipHashCode, the compressed zip file checksum
of the resource table file. /BuildReport/BuildLog.txt” file information can be viewed.
insert image description here

The occurrence of negative numbers does not affect the use, and the negative numbers that appear when the crc32 code is converted to int

3. Resource verification

First of all, there are actually three resource list files. In addition to the general table GameFrameworkVersion.XXXX.dat and GameFreamworkList.dat in the read-only directory, there is also a GameFreamworkList.dat resource list file in the read-write directory. This file records It is the resource file information in the read-write directory after the last update (if your application is started for the first time and the resource has not been updated, then this file does not exist, but if you have successfully updated the resource , it will be automatically generated for you by the GF framework)
Now first set the current variant of the resource module, because the step of verifying resources is to verify whether the resource file needs to be updated, and at the same time establish a resource information database for subsequent loading operations, So before you verify the resource information, be sure to set the current resource variant to be used, and then if you call the load resource method, you will search for resource information in the resource information database created at this time. The resource information of other variants other than the current variant will not be in the resource database. If the resource file of other variants is loaded, it will be treated as the case of no such resource information. Call
void ResourceComponent.SetCurrentVariant(string currentVariant) here
to set the variant, which is "" by default, that is, no variant. Then you can officially call
void ResourceComponent.CheckResources(CheckResourcesCompleteCallback checkResourcesCompleteCallback)
m_ResourceChecker.CheckResources(m_CurrentVariant, ignoreOtherVariant);
to start checking resources, CheckResources will read three resource list files for comparison,
If the GameFreamworkList.dat file does not exist in the read-only directory or the read-write directory, it will be treated as if there is no resource file in this directory.

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);

After reading the contents of the three resource list files, the resource information in the general table shall prevail, and the file hashcode value of the resource information recorded in the general table shall be used as the unique identifier.
If a certain resource information is not recorded in the two GameFreamworkList.dat resource tables, the resource file corresponding to this resource information will be treated as a resource file that needs to be updated and recorded in the pending update list.
In addition, if the resource information recorded in the general table is found to exist in both the read-only directory and the GameFreamworkList.dat resource table under the read-write directory, the corresponding resource file in the read-write directory will be deleted to save space ( Because there is already one resource file in the read-only directory, there is no need to store two).
Processing after reading the three files
CheckResources.RefreshCheckInfoStatus()
After the update list and resource information database are established, the resource file can be updated next.
insert image description here

4. Resource update

The resource update module will automatically update the resource file list based on the resource files we created in the previous step of verifying resources, go to the previously set download address, download resource files to the read-write directory in turn, and automatically generate the read-write directory after the download is complete. The GameFreamworkList.dat resource table file, this file records the resource file information in the read and write directory until the end of this update. It is convenient for the next update operation. Call
void UpdateResources(UpdateResourcesCompleteCallback updateResourcesCompleteCallback)
to start the update process. This process is very simple: download the file, and then generate the resource list file in the read-write directory

The specific content in GameFrameworkVersion.dat

Serialized from 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]
	}]

The specific content in GameFrameworkList.dat

LocalVersionList is serialized and
lacks asset information than above

{
    
    
	"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
	}, {
    
    

Guess you like

Origin blog.csdn.net/luoyikun/article/details/125649606