using TFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.Networking;
#if HybridCLR
using HybridCLR;
#endif
namespace TModule.Runtime {
public class HotfixManager : MonoBehaviour
{
public bool m_isEnableHotfix = true;
public string m_resServerUrl;
public string m_updateHandle;
public string m_versionFileName;
///
///本地资源存放路径
///
public string LocalResFilePath { get; private set; }
///
/// 本地版本文件存放路径
///
private string _loaclVersionPath;
///
/// 待下载资源列表
///
private List _NeedDownloadResList = new List();
///
/// 本地资源列表
///
private List _LocalResList = new List();
///
/// 检查版本文件进行事件
///
private Action OnCheckVersion;
///
/// 版本文件检查完成事件
///
private Action OnCheckVersionOver;
///
/// 版本文件检查出错事件
///
private Action OnCheckVersionError;
///
/// 检查进度
///
private float _checkProgress;
///
/// 超时时间
///
public const int DOWNLOADTIMEOUT = 5;
public float TotalSize
{
get
{
float szie = 0;
_NeedDownloadResList.ForEach(p => szie += (float)p.m_size);
return szie;
}
}
void Start()
{
if (m_isEnableHotfix)
{
}
}
///
/// 检查版本文件
///
public void InitCheckVersion(Action checkVersion, Action checkVersionOver, Action checkVersionError = null)
{
if (string.IsNullOrEmpty(AssetConfig.ResUrl))
{
Log.Error("未指定资源服务器地址");
return;
}
OnCheckVersion = checkVersion;
OnCheckVersionOver = checkVersionOver;
OnCheckVersionError = checkVersionError;
_checkProgress = 0;
string strVersionPath = AssetConfig.ResUrl + m_versionFileName;
StartCoroutine(DowloadVersion(strVersionPath));
}
///
/// 对比版本文件
///
///
private void OnInitVersionCallBack(List arg0)
{
_loaclVersionPath = LocalResFilePath + m_versionFileName;
if (FileOperations.FileExists(_loaclVersionPath))
{
List clienData = FileOperations.ReadJsonData>(_loaclVersionPath);
foreach (var item in arg0)
{
_checkProgress += 1.0f / arg0.Count / 2;
_checkProgress = _checkProgress >= 1 ? 1 : _checkProgress;
OnCheckVersion?.Invoke(_checkProgress);
VersionDataEntity dataEntity = clienData.Find(p => p.m_fullName == item.m_fullName);
//已有资源
if (dataEntity != null)
{
//对比MD5
if (dataEntity.m_md5 != item.m_md5)
_NeedDownloadResList.Add(item);
}
else
_NeedDownloadResList.Add(item);//新资源
}
}
else
arg0.ForEach(p =>
{
_NeedDownloadResList.Add(p);
_checkProgress += 1.0f / arg0.Count / 2;
_checkProgress = _checkProgress >= 1 ? 1 : _checkProgress;
OnCheckVersion?.Invoke(_checkProgress);
});
if (_NeedDownloadResList.Count > 0)
OnCheckVersionOver?.Invoke(TotalSize);
else
OnCheckVersionOver?.Invoke(0);
}
///
/// 下载版本文件
///
///
///
///
private IEnumerator DowloadVersion(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
www.timeout = DOWNLOADTIMEOUT;
yield return www.SendWebRequest();
while (!www.isDone)
{
_checkProgress = www.downloadProgress / 2;
OnCheckVersion?.Invoke(_checkProgress);
}
if (www.result != UnityWebRequest.Result.ProtocolError && www.result != UnityWebRequest.Result.ConnectionError)
{
string content = www.downloadHandler.text;
_checkProgress = 0.5f;
OnInitVersionCallBack(content.JsonStrToObject>());
Debug.Log(content);
}
else
{
Debug.Log("下载失败:" + www.error);
OnCheckVersionError?.Invoke(www.error);
}
}
///
/// 保存版本文件
///
private void SaveLoaclVersion() => FileOperations.WriteJsonData(_LocalResList, _loaclVersionPath);
///
/// 更新版本文件
///
///
public void ModifyLocaData(VersionDataEntity entity)
{
if (_LocalResList == null) return;
bool isExists = false;
for (int i = 0; i < _LocalResList.Count; i++)
{
if (_LocalResList[i].m_fullName.Equals(entity.m_fullName, StringComparison.CurrentCultureIgnoreCase))
{
_LocalResList[i].m_md5 = entity.m_md5;
_LocalResList[i].m_fullName = entity.m_fullName;
_LocalResList[i].m_size = entity.m_size;
isExists = true;
break;
}
}
if (!isExists)
{
_LocalResList.Add(entity);
}
SaveLoaclVersion();
}
private static void LoadMetadataForAOTAssemblies()
{
List aotMetaAssemblyFiles = new List()
{
"mscorlib.dll",
"System.dll",
"System.Core.dll",
};
/// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
/// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误
///
#if HybridCLR
HomologousImageMode mode = HomologousImageMode.SuperSet;
foreach (var aotDllName in aotMetaAssemblyFiles)
{
byte[] dllBytes = FileOperations.SafeReadAllBytes(AssetConfig.AssetBundleRootPath + aotDllName + ".bytes");
// 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
}
#else
Log.Error("当前非热更环境!请先安装HybridCLR");
#endif
}
}
}