using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using AssetManagement;

/// <summary>
/// 游戏启动更新检查
/// </summary>
public partial class LaunchUpdate : MonoBehaviour
{
private static string s_LogFilePath = Path.Combine(AssetDefine.ExternalSDCardsPath, "launch.log");
private static int s_LogFileSize = 1024 * 1024 * 5; //5m


public static bool LogEnabled = true;
public enum HotUpdateStepConst
{
LocalVer,
RemoteVer,
AssetsFiles,
RemoteAssetsFiles,
DownloadManifest,
DownloaderHotUpdateAssets,
}


public enum HotUpdateErrorCode : int
{
None = 0,
RemoteVerDownloaderError = 1000, //服务器版本文件下载异常
RemoteVerDecodeError = 2000, //服务器版本文件解析异常

RemoteFileListDownloaderError = 3000, //服务器文件列表下载异常
RemoteFileListDecodeError = 3002, //服务器文件列表解析异常
RemoteFileListMD5Error = 3003, //服务器文件列表md5校验失败

ManifestMD5Error = 4001, //清单文件md5校验失败
ManifestDownloaderError = 4003, //清单文件下载失败
}

public enum ProgressType
{
Checkup, //检查资源
Downloading, //下载资源
}

//注意如果不检查更新将直接用包内资源跑,也不会启动后台下载
public bool p_IsCheckUpdate = true;

public System.Action<float> onDownloadVerFileProgress;
public System.Action onUpdateComplete;

const string c_VersionFileName = "version.txt";
const string c_FileListFileName = "files";
const string c_ManifestFileName = "xassetmanifest";

private XVersionFile m_BuildingVersion;
//本地版本文件 sdcard->StreamingAssets
private XVersionFile m_LocalVersion;
//服务器版本文件
private XVersionFile m_RemoteVersion;

//内置文件列表
private XAssetsFiles m_BuildinFiles;
//本地文件列表
private XAssetsFiles m_LocalFiles;
//服务器文件列表
private XAssetsFiles m_RemoteFiles;
//远程文件列表在完成更新后保存在本地
private byte[] m_RemoteFilesBytes;

//启动更新列表
private List<XAssetsFiles.FileStruct> m_UpdateNeedDownload;
//后台更新列表
private List<XAssetsFiles.FileStruct> m_BackgroundNeedDownload;

//启动列表中是否有dll需要生启游戏
private bool m_LaunchDllUpdate = false;

private HotUpdateErrorCode m_ErrorCode;
private string m_ErrorStr;
void Start()
{
CheckUpdateLoggerSize();
RecordLogger(string.Empty);
RecordLogger(string.Empty);
RecordLogger("Start ..");
StartUpdate();
}

void StartUpdate()
{
m_ErrorCode = HotUpdateErrorCode.None;
m_ErrorStr = string.Empty;
StartCoroutine(StartUpHotUpdate());
}

IEnumerator StartUpHotUpdate()
{

//没有连接网络提示连接网络
if (!XUtility.IsNetworkValid())
{
RecordLogger(string.Format("StartUpHotUpdate -> NetworkValid .. Application.internetReachability = {0}", Application.internetReachability));
DefaultAlertGUI.Open(UpdateConst.GetLanguage(11301), UpdateConst.GetLanguage(11302), "", "", DefaultAlertGUI.ButtonOpt.None);
while (!XUtility.IsNetworkValid())
yield return 0;
DefaultAlertGUI.Close();
}

yield return HotUpdateStep(HotUpdateStepConst.LocalVer);

if (this.m_ErrorCode == HotUpdateErrorCode.None)
{
RecordLogger(string.Format("StartUpHotUpdate -> finish.."));

if (XConfig.defaultConfig.isSDKPattern)
HmlSdkProxy.instance.UploadUpdate(2);//热更新成功完成

OnUpdateComplete();
}
else
{
string title = UpdateConst.GetLanguage(11301);
string content = string.Format(UpdateConst.GetLanguage(11306), m_ErrorCode.ToString() + "\n" + m_ErrorStr);

DefaultAlertGUI alert = DefaultAlertGUI.Open(title, content, UpdateConst.GetLanguage(11305), "", DefaultAlertGUI.ButtonOpt.Sure);
UpdateUtility.ShowTextTip(string.Format(UpdateConst.GetLanguage(1201), this.m_ErrorCode));
XLogger.ReportException("更新检查异常", m_ErrorCode.ToString(), m_ErrorStr);
yield return alert.Wait();
StartUpdate();
}
}

//返回当前可信度最高的文件列表
XAssetsFiles GetValidFiles()
{
return m_RemoteFiles != null ? m_RemoteFiles : (m_LocalFiles != null ? m_LocalFiles : m_BuildinFiles);
}


IEnumerator HotUpdateStep(HotUpdateStepConst step)
{
if (this.m_ErrorCode != HotUpdateErrorCode.None)
{
RecordLogger(string.Format("HotUpdateStep -> m_ErrorCode = {0} m_ErrorStr = {1}", this.m_ErrorCode, this.m_ErrorStr));
yield break;
}
else
{
this.m_ErrorCode = HotUpdateErrorCode.None;
}

bool isSDKPattern = XConfig.defaultConfig.isSDKPattern;//SDK模式
switch (step)
{
case HotUpdateStepConst.LocalVer: //检查本地版本
{

CheckLocalVersion();
SetProgress(ProgressType.Checkup, 0.1f, UpdateConst.GetLanguage(11001));

if (m_LocalVersion == null)
{
RecordLogger(string.Format("HotUpdateStep -> {0} p_IsCheckUpdate = {1} Ver == null ", step, p_IsCheckUpdate));
}
else
{


RecordLogger(string.Format("HotUpdateStep -> {0} p_IsCheckUpdate = {1} Ver = {2} ", step, p_IsCheckUpdate, UpdateUtility.GetVersionStrInfo(m_LocalVersion)));
}

if (p_IsCheckUpdate)
yield return HotUpdateStep(HotUpdateStepConst.RemoteVer);
else //不检更新
CheckLocalAssetFiles();

//暂定为第一次安装解压完成
if (isSDKPattern && isFirstInstall)
HmlSdkProxy.instance.UploadUnzip(2);

break;
}
case HotUpdateStepConst.RemoteVer: //检查服务器版本
{
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.RemoteVer. start");
}

yield return CheckRemoteVersionCoroutine();
SetProgress(ProgressType.Checkup, 0.2f);

if (m_RemoteVersion == null)
{
RecordLogger(string.Format("HotUpdateStep -> {0} p_IsCheckUpdate = {1} Ver == null ", step, p_IsCheckUpdate));
}
else
{
RecordLogger(string.Format("HotUpdateStep -> {0} p_IsCheckUpdate = {1} Ver = {2} ", step, p_IsCheckUpdate, UpdateUtility.GetVersionStrInfo(m_RemoteVersion)));
}

if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.RemoteVer. end");
}

yield return HotUpdateStep(HotUpdateStepConst.AssetsFiles);
break;
}
case HotUpdateStepConst.AssetsFiles: //检查本地文件列表
{
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.AssetsFiles. start");
}

CheckLocalAssetFiles();
SetProgress(ProgressType.Checkup, 0.3f, UpdateConst.GetLanguage(11003));
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.AssetsFiles. end");
}

RecordLogger(string.Format("HotUpdateStep -> {0} isVerChange = {1}", step, isVerChange()));

if (isVerChange()) //版本发生变化
yield return HotUpdateStep(HotUpdateStepConst.RemoteAssetsFiles);
else //版本未发生变化校验本地文件
yield return HotUpdateStep(HotUpdateStepConst.DownloaderHotUpdateAssets);
break;
}
case HotUpdateStepConst.RemoteAssetsFiles: //检查远程文件列表
{
RecordLogger(string.Format("HotUpdateStep -> {0}", step));
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.RemoteAssetsFiles. start");
}
yield return CheckRemoteAssetFilesCoroutine();
SetProgress(ProgressType.Checkup, 0.4f);
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.RemoteAssetsFiles. end");
}

yield return HotUpdateStep(HotUpdateStepConst.DownloadManifest);
break;
}
case HotUpdateStepConst.DownloadManifest: //下载清单文件
{
RecordLogger(string.Format("HotUpdateStep -> {0}", step));
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.DownloadManifest. start");
}

yield return CheckDownloadMainfest();

SetProgress(ProgressType.Checkup, 0.5f);

if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.DownloadManifest. end");
}
yield return HotUpdateStep(HotUpdateStepConst.DownloaderHotUpdateAssets);
break;
}
case HotUpdateStepConst.DownloaderHotUpdateAssets: //收集并下载启动更新资源
{
RecordLogger(string.Format("HotUpdateStep -> {0}", step));
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.DownloaderHotUpdateAssets. start");
}

if (isSDKPattern)
HmlSdkProxy.instance.UploadUpdate(1);

yield return CollectNeedDownloadFiles();
SetProgress(ProgressType.Checkup, 1f);
if (LogEnabled)
{
XLogger.DEBUG("LaunchUpdate::HotUpdateStep HotUpdateStepConst.DownloaderHotUpdateAssets. end");
}

UpdateUtility.ShowTextTip(string.Format(UpdateConst.GetLanguage(5000), m_UpdateNeedDownload.Count, m_BackgroundNeedDownload.Count, m_LaunchDllUpdate, GetValidFiles().p_FileCount));
if (LogEnabled)
XLogger.INFO(string.Format("m_UpdateNeedDownload:{0} m_BackgroundNeedDownload:{1} m_LaunchDllUpdate:{2} m_RemoteFiles:{3}", m_UpdateNeedDownload.Count, m_BackgroundNeedDownload.Count, m_LaunchDllUpdate, GetValidFiles().p_FileCount));


yield return DownloadUpdateAssets();

SetProgress(ProgressType.Downloading, 1f);
break;
}
default:
break;
}
}

void RecordLogger(string content)
{
XLogger.RecordLog(s_LogFilePath, content, "Launch ");
}

void CheckUpdateLoggerSize()
{
FileInfo finfo = new FileInfo(s_LogFilePath);
if (finfo.Exists && finfo.Length >= s_LogFileSize)
finfo.Delete();
}

void SetProgress(ProgressType t, float v, string desc = "")
{
if (t == ProgressType.Checkup)
{
//DefaultLoaderGUI.SetProgressText(UpdateConst.GetLanguage(10002));
DefaultLoaderGUI.SetProgress(v);
}
else
{
//DefaultLoaderGUI.SetProgressText(UpdateConst.GetLanguage(10003));
DefaultLoaderGUI.SetProgress(v);
}

if (!string.IsNullOrEmpty(desc))
{
DefaultLoaderGUI.SetProgressText(desc);
}

//Debug.Log(t + " " + v);
}


void OnUpdateComplete()
{
UpdateUtility.ShowTextTip(UpdateConst.GetLanguage(10000));

if (m_RemoteFiles != null)
{
string verpath = AssetDefine.ExternalSDCardsPath + c_VersionFileName;
XFileUtility.WriteText(verpath, JsonUtility.ToJson(m_RemoteVersion, true));
string flspath = AssetDefine.ExternalSDCardsPath + c_FileListFileName;
XFileUtility.WriteBytes(flspath, m_RemoteFilesBytes);
m_RemoteFilesBytes = null;
}


RecordLogger(string.Format("OnUpdateComplete -> m_LaunchDllUpdate:{0} XConfig.defaultConfig.isDllUpdate:{1}", m_LaunchDllUpdate, XConfig.defaultConfig.isDllUpdate));
#if !UNITY_EDITOR
if (m_LaunchDllUpdate && XConfig.defaultConfig.isDllUpdate)
{
//并重启
UpdateUtility.InitDll();
return;
}
#endif

if (onUpdateComplete != null)
{
onUpdateComplete.Invoke();
}


if (p_IsCheckUpdate)
{
//启动后台下载
StartCoroutine(LaunchBackgroundDownloader());
}
}
}
using System;
using UnityEngine;
using UnityEngine.Networking;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using AssetManagement;

public partial class LaunchUpdate
{
//是否第一次安装
private bool isFirstInstall = false;
//检查本地版本
void CheckLocalVersion()
{
UpdateUtility.ShowTextTip(UpdateConst.GetLanguage(1000));
if (LogEnabled)
XLogger.INFO("LaunchUpdate::CheckVersion. begin");
string sdcardVerPath = Path.Combine(AssetDefine.ExternalSDCardsPath, c_VersionFileName);

bool sdcardValidate = false;

if (File.Exists(sdcardVerPath))
{
//扩展卡版本文件载入
string versionJson = File.ReadAllText(sdcardVerPath);
if (string.IsNullOrEmpty(versionJson))
{
//内容为空
XLogger.INFO(string.Format("LaunchUpdate::CheckVersion() sdcard version is Empty ! path={0}", sdcardVerPath));
UpdateUtility.ShowTextTip(UpdateConst.GetLanguage(1010));

}
else
{
try
{
m_LocalVersion = UpdateUtility.DeVersion(versionJson, sdcardVerPath);
sdcardValidate = true;
}
catch (System.Exception e)
{
//解析异常
XLogger.INFO(string.Format("LaunchUpdate::CheckVersion() sdcard version decode error ! path={0} error={1} data={2}", sdcardVerPath, e.ToString(), versionJson));
UpdateUtility.ShowTextTip(UpdateConst.GetLanguage(1020));
}
}
}
else
{
//暂定为第一次安装解压,有好的方法在移动
isFirstInstall = true;
if (XConfig.defaultConfig.isSDKPattern)
HmlSdkProxy.instance.UploadUnzip(1);
}

//若扩展卡版本文件不存在或是出现异常则使用内置版本文件
if (!sdcardValidate)
{
//为了正确识别覆盖安装,若内置版本

//内置版本文件载入
if (LogEnabled)
XLogger.INFO(string.Format("LaunchUpdate::CheckVersion() load buildin version ! path={0}", sdcardVerPath));
string buildinVerPath = Path.Combine(AssetDefine.BuildinAssetPath, c_VersionFileName);

string versionJson = string.Empty;
string error = string.Empty;

versionJson = XFileUtility.ReadStreamingFile(buildinVerPath, out error);

if (string.IsNullOrEmpty(error))
{
//内容为空
if (string.IsNullOrEmpty(versionJson))
{

UpdateUtility.ShowTextTip(UpdateConst.GetLanguage(1100));
XLogger.INFO(string.Format("LaunchUpdate::CheckVersion() buildin version error ! path={0} error={1}", buildinVerPath, "content is Empty"));
}
else
{
try
{
m_LocalVersion = UpdateUtility.DeVersion(versionJson, buildinVerPath);
}
catch (System.Exception e)
{
UpdateUtility.ShowTextTip(UpdateConst.GetLanguage(1101));
//解析异常
XLogger.INFO(string.Format("LaunchUpdate::CheckVersion() buildin version decode error! path={0} error={1} data={2}", buildinVerPath, e.ToString(), versionJson));
}
}
}
}


if (LogEnabled)
XLogger.INFO("LaunchUpdate::CheckVersion. end");

XAssetsFiles.s_CurrentVersion = m_LocalVersion;
//显示版本号
UpdateUtility.SetUIVersionInfo(m_LocalVersion, null);
}

//检查远程版本
IEnumerator CheckRemoteVersionCoroutine()
{
string random = DateTime.Now.ToString("yyyymmddhhmmss");
string remoteVerUrl = AssetDefine.RemoteDownloadUrl + c_VersionFileName + "?v=" + random;
RecordLogger(string.Format("CheckRemoteVersionCoroutine. remoteVerUrl: {0}", remoteVerUrl));
using (UnityWebRequest uwr = UnityWebRequest.Get(remoteVerUrl))
{
UnityWebRequestAsyncOperation async = uwr.SendWebRequest();
while (!async.isDone)
{
if (onDownloadVerFileProgress != null) onDownloadVerFileProgress.Invoke(async.progress);
SetProgress(ProgressType.Checkup, 0.1f + async.progress * 0.1f, UpdateConst.GetLanguage(11002));
yield return 0;
}

if (!string.IsNullOrEmpty(uwr.error) || uwr.isHttpError || uwr.isNetworkError)
{
m_ErrorCode = HotUpdateErrorCode.RemoteVerDownloaderError;
XLogger.ERROR(string.Format("LaunchUpdate::CheckRemoteVersionCoroutine() remote version download error ! remoteVerUrl={0} error={1} url={2}", remoteVerUrl, uwr.error, remoteVerUrl));
yield break;
}

string jsonData = uwr.downloadHandler.text;
if (string.IsNullOrEmpty(jsonData))
{
m_ErrorCode = HotUpdateErrorCode.RemoteVerDecodeError;
XLogger.ERROR(string.Format("LaunchUpdate::CheckRemoteVersionCoroutine() remote version content is Empty ! path={0} error={1} url={2}", remoteVerUrl, "content is Empty", remoteVerUrl));
}
else
{
try
{

m_RemoteVersion = UpdateUtility.DeVersion(jsonData, remoteVerUrl);
}
catch (System.Exception e)
{
m_ErrorCode = HotUpdateErrorCode.RemoteVerDecodeError;
XLogger.INFO(string.Format("LaunchUpdate::CheckRemoteVersionCoroutine() remote version decode error! path={0} error={1} data={2}", remoteVerUrl, e.ToString(), jsonData));
}
}
}

XAssetsFiles.s_CurrentVersion = m_RemoteVersion;
//显示版本号
UpdateUtility.SetUIVersionInfo(m_LocalVersion, m_RemoteVersion);
}

//版本是否发生改变
bool isVerChange()
{
//没有文件列表
if (GetValidFiles() == null)
return true;

//如果本地文件列表存在表示更新过,但是清单文件意外丢失
if (File.Exists(AssetDefine.ExternalSDCardsPath + c_FileListFileName) && !File.Exists(AssetDefine.ExternalSDCardsPath + c_ManifestFileName))
return true;

//版本改表
if (m_LocalVersion != null && m_RemoteVersion != null)
{
#if UNITY_EDITOR
//编辑器不检查 代码和预制体
if ( m_LocalVersion.p_ArtVersion.svnVer != m_RemoteVersion.p_ArtVersion.svnVer)
{
return true;
}

#else

if (m_LocalVersion.p_DevVersion.svnVer != m_RemoteVersion.p_DevVersion.svnVer ||
m_LocalVersion.p_ArtVersion.svnVer != m_RemoteVersion.p_ArtVersion.svnVer)
{
return true;
}

#endif

return false;
}
return true;
}

//检查本地文件列表
void CheckLocalAssetFiles()
{
if (LogEnabled)
XLogger.DEBUG("LaunchUpdate::CheckLocalFileList. start");
string sdcardPath = Path.Combine(AssetDefine.ExternalSDCardsPath, c_FileListFileName);
if (File.Exists(sdcardPath))
{
//扩展卡版本文件载入
string jsonData = UpdateUtility.ReadAssetList(AssetBundle.LoadFromFile(sdcardPath));
if (string.IsNullOrEmpty(jsonData))
{
//内容为空
XLogger.DEBUG(string.Format("LaunchUpdate::CheckLocalFileList() sdcard assetFiles is Empty ! path={0}", sdcardPath));
}
else
{
try
{
m_LocalFiles = UpdateUtility.DeFileList(jsonData);
XAssetsFiles.s_CurrentAssets = m_LocalFiles;
}
catch (System.Exception e)
{
//解析异常
XLogger.DEBUG(string.Format("LaunchUpdate::CheckLocalFileList() sdcard assetFiles decode error ! path={0} error={1} data={2}", sdcardPath, e.ToString(), jsonData));
}
}
}


//内置文件列表
//if (!sdcardValidate)
{
//内置版本文件载入
if (LogEnabled)
XLogger.DEBUG(string.Format("LaunchUpdate::CheckLocalFileList() load buildin assetFiles ! path={0}", sdcardPath));
string buildinPath = Path.Combine(AssetDefine.BuildinAssetPath, c_FileListFileName);

string jsonData = string.Empty;
//string error = string.Empty;

jsonData = UpdateUtility.ReadBuildinAssetList(buildinPath);

if (string.IsNullOrEmpty(jsonData))
{
//内容为空
XLogger.DEBUG(string.Format("LaunchUpdate::CheckLocalFileList() buildin assetFiles error ! path={0} error={1}", buildinPath, "content is Empty"));
}
else
{
try
{
m_BuildinFiles = UpdateUtility.DeFileList(jsonData);
XAssetsFiles.s_BuildingtAssets = m_BuildinFiles;
if (XAssetsFiles.s_CurrentAssets == null)
XAssetsFiles.s_CurrentAssets = m_BuildinFiles;
}
catch (System.Exception e)
{
//解析异常
XLogger.DEBUG(string.Format("LaunchUpdate::CheckLocalFileList() buildin version decode error! path={0} error={1} data={2}", buildinPath, e.ToString(), jsonData));
}
}
}
if (LogEnabled)
XLogger.DEBUG("LaunchUpdate::CheckLocalFileList. end");
}


//检查服务器文件列表
IEnumerator CheckRemoteAssetFilesCoroutine()
{
string tempPath = AssetManager.Instance.AssetLoaderOptions.GetAssetDownloadSavePath(c_FileListFileName + ".dtemp");
AssetFileThreadDownloader downloader = AssetFileThreadDownloader.Get(c_FileListFileName, tempPath, m_RemoteVersion.p_files_md5, m_RemoteVersion.p_files_md5);

while (!downloader.IsDone())
{
SetProgress(ProgressType.Checkup, 0.3f + downloader.progress * 0.1f, UpdateConst.GetLanguage(11004));
yield return 0;
}

//下载出现异常
if (!string.IsNullOrEmpty(downloader.Error))
{
m_ErrorCode = HotUpdateErrorCode.RemoteFileListDownloaderError;

m_ErrorStr = string.Format("LaunchUpdate::CheckRemoteAssetFilesCoroutine() downloader err ! path={0} error={1}", downloader.WebUrl, downloader.Error);
XLogger.ERROR(m_ErrorStr);
yield break;
}


try
{
if (File.Exists(downloader.DownloadPath))
{
m_RemoteFilesBytes = File.ReadAllBytes(downloader.DownloadPath);
File.Delete(downloader.DownloadPath);
}

}
catch (System.Exception ex)
{
XLogger.ERROR(string.Format("LaunchUpdate::CheckRemoteAssetFilesCoroutine() downloader err ! path={0} error={1}", downloader.WebUrl, ex.ToString()));
yield break;
}


string jsonData = string.Empty;
try
{
//解析
jsonData = UpdateUtility.ReadAssetList(AssetBundle.LoadFromMemory(m_RemoteFilesBytes));
}
catch (System.Exception ex)
{
XLogger.ERROR(string.Format("LaunchUpdate::CheckRemoteAssetFilesCoroutine() path={0} error={1}", downloader.WebUrl, ex.ToString()));
}


if (string.IsNullOrEmpty(jsonData))
{
//解析异常
m_ErrorCode = HotUpdateErrorCode.RemoteFileListDecodeError;
m_ErrorStr = string.Format("LaunchUpdate::CheckRemoteAssetFilesCoroutine() remote assetFiles content is Empty ! path={0} error={1}", downloader.WebUrl, "content is Empty");
XLogger.ERROR(m_ErrorStr);
}
else
{
try
{

m_RemoteFiles = UpdateUtility.DeFileList(jsonData);
XAssetsFiles.s_CurrentAssets = m_RemoteFiles;
}
catch (System.Exception e)
{
m_ErrorCode = HotUpdateErrorCode.RemoteFileListDecodeError;
m_ErrorStr = string.Format("LaunchUpdate::CheckRemoteAssetFilesCoroutine() remote assetFiles decode error! path={0} error={1} data={2}", downloader.WebUrl, e.ToString(), jsonData);
XLogger.ERROR(m_ErrorStr);
}
}
}

//下载清单文件
IEnumerator CheckDownloadMainfest()
{
AssetFileThreadDownloader downloader = AssetFileThreadDownloader.Get(c_ManifestFileName, null, m_RemoteVersion.p_manifest_md5);
while (!downloader.IsDone())
{
SetProgress(ProgressType.Checkup, 0.4f + downloader.GetProgress() * 0.1f, UpdateConst.GetLanguage(11004));
yield return 0;
}
yield return downloader;

if (!string.IsNullOrEmpty(downloader.Error))
{
if (downloader.state == AssetDownloader.State.ErrorMd5)
m_ErrorCode = HotUpdateErrorCode.ManifestMD5Error;
else
m_ErrorCode = HotUpdateErrorCode.ManifestDownloaderError;

m_ErrorStr = string.Format("LaunchUpdate::CheckDownloadMainfest() downloader err ! path={0} error={1}", downloader.WebUrl, downloader.Error);
XLogger.ERROR(m_ErrorStr);
yield break;
}
}

//收集需要下载的文件
IEnumerator CollectNeedDownloadFiles()
{
int downloadTag = XConfig.defaultConfig.initDownloadTag;
RecordLogger(string.Format("HotUpdateStep -> {0} downloadTag={1}.", "CollectNeedDownloadFiles", downloadTag));
m_UpdateNeedDownload = new List<XAssetsFiles.FileStruct>();
m_BackgroundNeedDownload = new List<XAssetsFiles.FileStruct>();

XAssetsFiles files = GetValidFiles();//服务器、本地、包内
XAssetsFiles localFiles = m_LocalFiles != null ? m_LocalFiles : m_BuildinFiles;

int count = 0;
int totalCount = files.p_AllFiles.Count;
bool isdone = false;
System.Threading.ThreadPool.QueueUserWorkItem((object state) =>
{
if (LogEnabled)
XLogger.DEBUG("LaunchUpdate::CollectNeedDownloadFiles. start");
foreach (var asset in files.p_AllFiles)
{
count++;
string sdcardPath = AssetDefine.ExternalSDCardsPath + asset.path;
//string fileMd5 = string.Empty;
bool exists = File.Exists(sdcardPath);
//if (exists)
//fileMd5 = XFileUtility.FileMd5(sdcardPath);

XAssetsFiles.FileStruct add = null;

//本地或首包
XAssetsFiles.FileStruct file = null;

//是否为最新 //sd卡有并且md5也对应得上 表示为最新的文件
bool isNewest = exists && localFiles != null &&
localFiles.allFilesMap.TryGetValue(asset.path, out file) && file.md5 == asset.md5;

bool isBuilding = (asset.options & XAssetsFiles.FileOptions.BUILDING) == XAssetsFiles.FileOptions.BUILDING;
if (isBuilding) //是否为首包
{
//此资源为内置/首包资源
//但内置/首包中不存在 或者 已经发生变化!需要下载
if (m_BuildinFiles == null || !m_BuildinFiles.allFilesMap.TryGetValue(asset.path, out file) || file.md5 != asset.md5)
{
//并且本地没有最新的
if (!isNewest)
add = asset;
}
}
else
{
//不是内置/首包资源

// 本地不存在 或者 文件不是最新的!需要下载 md5超慢放弃
//if (string.IsNullOrEmpty(fileMd5) || fileMd5 != asset.md5)
//{
// add = asset;
//}

// 本地不存在 或者 文件不是最新的!需要下载
if (!exists || localFiles == null || !localFiles.allFilesMap.TryGetValue(asset.path, out file) || file.md5 != asset.md5)
{
add = asset;
}
}

if (add == null)
continue;

//本地的文件不是最新的文件了需要删掉
if (exists)
{
if (((add.options & XAssetsFiles.FileOptions.LUA) == XAssetsFiles.FileOptions.LUA))
{ }
else
File.Delete(sdcardPath);
}


if (downloadTag != -1 && downloadTag == add.tag)
{
//启动需要下载的扩展包
m_UpdateNeedDownload.Add(add);
if ((add.options & XAssetsFiles.FileOptions.DLL) == XAssetsFiles.FileOptions.DLL)
m_LaunchDllUpdate = true;

RecordLogger(string.Format("tagDownload -> name={0} size={1} tag={2} exist={3} isBuilding={4} smd5={5} lmd5={6}",
add.path, XUtility.FormatBytes(add.size), add.tag, exists, isBuilding, add.md5, file != null ? file.md5 : "null"));

}
else if ((add.options & XAssetsFiles.FileOptions.LAUNCHDOWNLOAD) == XAssetsFiles.FileOptions.LAUNCHDOWNLOAD)
{
//启动需要下载
m_UpdateNeedDownload.Add(add);
if ((add.options & XAssetsFiles.FileOptions.DLL) == XAssetsFiles.FileOptions.DLL)
m_LaunchDllUpdate = true;

RecordLogger(string.Format("LaunchDownload -> name={0} size={1} tag={2} exist={3} isBuilding={4} smd5={5} lmd5={6}",
add.path, XUtility.FormatBytes(add.size), add.tag, exists, isBuilding, add.md5, file != null ? file.md5 : "null"));
}
else
{
//后台需要下载
m_BackgroundNeedDownload.Add(add);

}
}
isdone = true;
if (LogEnabled)
XLogger.DEBUG("LaunchUpdate::CollectNeedDownloadFiles. end");
});


while (!isdone)
{
float p = (float)count / (float)totalCount;
SetProgress(ProgressType.Checkup, 0.5f + p * 0.5f, string.Format(UpdateConst.GetLanguage(11005), p * 100));
yield return 0;
}

SetProgress(ProgressType.Checkup, 1f, string.Format(UpdateConst.GetLanguage(11005), 100f));
}

//下载启动更新文件
IEnumerator DownloadUpdateAssets()
{
if (m_UpdateNeedDownload.Count < 1)
{
RecordLogger(string.Format("HotUpdateStep -> {0} count={1} ", "DownloadUpdateAssets", 0));
SetProgress(ProgressType.Downloading, 1);
yield break;
}

bool isFastUpdate = true;
AssetFileDownloadQueue download = gameObject.AddComponent<AssetFileDownloadQueue>();
download.onBeginStep = () => { RecordLogger(string.Format("HotUpdateStep::onBeginDownload -> {0} ", download.currentDownloader.WebUrl)); };
download.onEndStep = () =>
{
string err = download.currentDownloader.Error;
err = string.IsNullOrEmpty(err) ? "" : "Error=" + err;
RecordLogger(string.Format("HotUpdateStep::onEndStep -> {0} {1}", download.currentDownloader.WebUrl, err));
};

download.errorPause = true;
download.SetFiles(m_UpdateNeedDownload);

RecordLogger(string.Format("HotUpdateStep -> {0} count={1} totalSize={2}.", "DownloadUpdateAssets", download.totalFileCount, XUtility.FormatBytes(download.bytesTotal)));

float downloadAlertSize = XConfig.defaultConfig.downloadAlertSize;

//提示下载大小

float bytesSize = download.bytesTotal * XConfig.defaultConfig.downloadSizeFactor;
float downSize = Mathf.Round((bytesSize / 1048576.0f) * 100.0f)/100.0f;
Debug.Log("downSize: " + downSize);
if (downSize >= downloadAlertSize)
{
string tipContent = string.Format(UpdateConst.GetLanguage(XUtility.IsNetworkWifi() ? 10010 : 10011), XUtility.FormatBytes(bytesSize));
DefaultAlertGUI alertDownloadTip = DefaultAlertGUI.Open("", tipContent, UpdateConst.GetLanguage(11206), "", DefaultAlertGUI.ButtonOpt.Sure);
yield return alertDownloadTip.Wait();
}



download.StartDownload();
float lastProgress = 0;
while (!download.isDone)
{
if (download.isPause)
{
//下载出现异常

if (!XUtility.IsNetworkValid())
{
//下载过程中把网络关掉了
DefaultAlertGUI.Open(UpdateConst.GetLanguage(11301), UpdateConst.GetLanguage(11302), "", "", DefaultAlertGUI.ButtonOpt.None);
while (!XUtility.IsNetworkValid()) yield return 0;
DefaultAlertGUI.Close();
download.StartDownload();
}
else
{

string content = string.Format(UpdateConst.GetLanguage(11303), download.currentFS.path + " \n" + download.error);
string title = UpdateConst.GetLanguage(11301);
string sureStr = UpdateConst.GetLanguage(11304);
DefaultAlertGUI alert = DefaultAlertGUI.Open(title, content, sureStr, "", DefaultAlertGUI.ButtonOpt.Sure);

XLogger.ReportException("更新下载异常", download.currentFS.path, download.error);

//等待玩家点击重试
yield return alert.Wait();
download.StartDownload();
}
}
else
{
string tip = string.Empty;
if (isFastUpdate || Time.frameCount % 20 == 0)
{
tip = string.Format(UpdateConst.GetLanguage(11006),
XUtility.FormatBytes(download.bytesReceived * XConfig.defaultConfig.downloadSizeFactor),
XUtility.FormatBytes(download.bytesTotal * XConfig.defaultConfig.downloadSizeFactor),
Mathf.Clamp(download.currentFileIdx + 1, 0, download.totalFileCount),
Mathf.Clamp(download.totalFileCount, 0, download.totalFileCount),
XUtility.FormatBytes(download.downloadSpeed));
}


if (download.progress > lastProgress)
lastProgress = download.progress;
SetProgress(ProgressType.Downloading, lastProgress, tip);
}
yield return 0;
}
}

IEnumerator CollectBackgroundDownloaderFiles()
{
//版本没有发生变化,将不会走到 CollectNeedDownloadFiles 不会收集后台需要下载的资源
if (m_BackgroundNeedDownload == null)
{
RecordLogger(string.Format("HotUpdateStep -> {0}", "CollectBackgroundDownloaderFiles"));
XAssetsFiles localFiles = m_LocalFiles != null ? m_LocalFiles : m_BuildinFiles;
XAssetsFiles files = GetValidFiles();

int count = 0;
int totalCount = files.p_AllFiles.Count;
bool isdone = false;

System.Threading.ThreadPool.QueueUserWorkItem((object state) =>
{
if (LogEnabled)
XLogger.DEBUG("LaunchUpdate::CollectBackgroundDownloaderFiles. start");

m_BackgroundNeedDownload = new List<XAssetsFiles.FileStruct>();
foreach (var asset in files.p_AllFiles)
{
count++;
string sdcardPath = AssetDefine.ExternalSDCardsPath + asset.path;

bool exists = File.Exists(sdcardPath);

XAssetsFiles.FileStruct add = null;

XAssetsFiles.FileStruct file;
if (m_BuildinFiles == null || !m_BuildinFiles.allFilesMap.TryGetValue(asset.path, out file) || file.md5 != asset.md5)
{
//首包不存在
add = asset;

}
if (!exists || localFiles == null || !localFiles.allFilesMap.TryGetValue(asset.path, out file) || file.md5 != asset.md5)
{
//本地不存在此资源
add = asset;
}
else
{
//本地存在的文件,究竟需不需要md5验证下是不是发生改变,md5验证将会延长文件校验时间
//如果不用文件本身的md5,可能会有一种情况。玩家在后台下载的过程中,关掉游戏,此时本地文件列表是服务器最新文件列表,
//再次启动游戏文件列表对比将筛选不出来发生改变的同名文件,这个时候文件的md5跟列表中的md5对比就可以解决.
//try
//{
// string fmd5 = XFileUtility.FileMd5(sdcardPath);
// if (localFiles == null || !localFiles.allFilesMap.TryGetValue(asset.path, out file) || fmd5 != asset.md5)
// {
// add = asset;
// }
//}
//catch (System.Exception ex)
//{
// XLogger.ERROR(string.Format("LaunchUpdate::CollectBackgroundDownloaderFiles. path = {0} error = {1}", asset.path, ex.ToString()));
//}
}

if (asset == null)
continue;

if (exists)
{
if (((add.options & XAssetsFiles.FileOptions.LUA) == XAssetsFiles.FileOptions.LUA)) { }
else
File.Delete(sdcardPath);
}
m_BackgroundNeedDownload.Add(asset);
}

isdone = true;
if (LogEnabled)
XLogger.DEBUG("LaunchUpdate::CollectBackgroundDownloaderFiles. end");
});

while (!isdone)
yield return 0;
}
}

//启动后台文件下载
IEnumerator LaunchBackgroundDownloader()
{
yield return CollectBackgroundDownloaderFiles();
bool backgroundDownload = XConfig.defaultConfig.backgroundDownload;

UpdateUtility.ShowTextTip(string.Format(UpdateConst.GetLanguage(5001), m_BackgroundNeedDownload.Count + " " + backgroundDownload));
BackgroundDownloadQueue.Instance.SetFiles(m_BackgroundNeedDownload);

int totalSize = 0;
//tag各类型的数量
Dictionary<int, int> tagType = new Dictionary<int, int>();
foreach (var asset in m_BackgroundNeedDownload)
{
if (!tagType.ContainsKey(asset.tag))
tagType.Add(asset.tag, 0);
++tagType[asset.tag];
totalSize += asset.size;
}



RecordLogger(string.Format("HotUpdateStep -> {0} count={1} totalSize={2}. backgroundDownload={3}", "LaunchBackgroundDownloader",
m_BackgroundNeedDownload.Count, XUtility.FormatBytes(totalSize), backgroundDownload));

foreach (var item in tagType)
RecordLogger(string.Format(" -> tag={0} count={1}", item.Key, item.Value));

if (backgroundDownload)
{
BackgroundDownloadQueue.Instance.StartAutoDownload();
}

//#if UNITY_IOS
// if (!HmlPHPData.VerifyApp)
// {
// BackgroundDownloadQueue.Instance.StartAutoDownload();
// }
//#endif
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class UpdateConst
{
private static Dictionary<int, string> s_UpdateLanguage = new Dictionary<int, string>()
{
{1000,@"<color=#00800BFF>检查游戏版本!</color>"},
{1010,@"<color=red>内存卡版本文件内容为空!</color>"},
{1020,@"<color=red>内存卡版本文件解析异常!</color>"},

{1100,@"<color=red>内置版本文件内容为空!</color>"},
{1101,@"<color=red>内置版本文件解析异常!</color>"},

{1201,@"<color=red>版本检查发生异常! {0}</color>"},

{5000,@"<color=#00800BFF>启动更新:{0} 后台更新:{1} CSharp重启:{2} 总文件数:{3}</color>"},
{5001,@"<color=#00800BFF>后台下载:{0}</color>"},


{5005,@"<color=yellow>下载成功:{0}/{1} {2}</color>"},
{5006,@"<color=red>下载失败:{0} error: {1}</color>"},




{10000,@"<color=#00800BFF>版本更新完成!</color>"},
{10002,@"<color=#00800BFF>正在校验文件</color>"},
{10003,@"<color=#00800BFF>正在更新文件</color>"},

{10010,"游戏发现新内容,立即更新体验!\n <size=25>(资源大小为<color=#00800BFF>{0}</color>流量)</size>"},
{10011,"游戏发现新内容,立即更新体验!\n <size=25>(资源大小为<color=#00800BFF>{0}</color>流量,建议连接WIFI)</size>"},


{11001,@"检查版本"},
{11002,@"检查服务器版本"},
{11003,@"检查本地文件列表"},
{11004,@"下载资产清单"},
{11005,@"校验本地文件{0:F}%"},
{11006,@"正在更新文件{0}/{1} 文件数{2}/{3} {4}/s"},
{11007,@"正在初始化资源..."},
{11008,@"正在初始化游戏配置..."},
{11009,@"初始化完成,即将进入游戏"},

{11206,@"确定"},
{11207,@"取消"},

{11301,@"提示"},
{11302,"<color=red>当前没有可使用的网络,请连接正确的网络4G/Wifi!</color>\n<color=#00800BFF>连接网络后将自动继续</color>"},
{11303,"<color=red>文件下载发生异常!\n<size=25><color=#00800BFF>可以尝试重试或是重启游戏修复</color></size>\n<size=12>{0}</size></color>"},
{11304,@"再试一把"},
{11305,@"重试"},
{11306,"资源检查发生异常!\n<color=red><size=12>{0}</size></color>\n请点击【重试】进行重新加载\n<color=#00800BFF><size=22>(若多次重试无效,请联系客服)</size></color>"},
{11307,@"获取资源地址失败,请联系客服!是否重试?"},

{11308,@"<color=red>检测到未开启OpenGL</color> 为了您更好的体验游戏,<color=#00800BFF>请前往【置中心-引擎设置-画质渲染模式】勾选OpenGL模式</color>"},


{12000,@"声音组件初始化失败!"},
{12001,@"材质组件初始化失败!"},
};

private static Dictionary<int, string> s_IOSLanguage = new Dictionary<int, string>()
{
{1000,@"<color=#00800BFF>检查游戏版本!</color>"},
{1010,@"<color=red>内存卡版本文件内容为空!</color>"},
{1020,@"<color=red>内存卡版本文件解析异常!</color>"},

{1100,@"<color=red>内置版本文件内容为空!</color>"},
{1101,@"<color=red>内置版本文件解析异常!</color>"},

{1201,@"<color=red>版本检查发生异常! {0}</color>"},

{5000,@"<color=#00800BFF>启动更新:{0} 后台更新:{1} CSharp重启:{2} 总文件数:{3}</color>"},
{5001,@"<color=#00800BFF>后台下载:{0}</color>"},


{5005,@"<color=yellow>下载成功:{0}/{1} {2}</color>"},
{5006,@"<color=red>下载失败:{0} error: {1}</color>"},




{10000,@"<color=#00800BFF>版本更新完成!</color>"},
{10002,@"<color=#00800BFF>正在校验文件</color>"},
{10003,@"<color=#00800BFF>正在更新文件</color>"},

{10010,"游戏发现新内容,立即更新体验!\n <size=25>(资源大小为<color=#00800BFF>{0}</color>流量)</size>"},
{10011,"游戏发现新内容,立即更新体验!\n <size=25>(资源大小为<color=#00800BFF>{0}</color>流量,建议连接WIFI)</size>"},


//{11001,@"检查版本"},
//{11002,@"检查服务器版本"},
//{11003,@"检查本地文件列表"},
//{11004,@"下载资产清单"},
//{11005,@"校验本地文件{0:F}%"},
//{11006,@"正在更新文件{0}/{1} 文件数{2}/{3} {4}/s"},
//{11007,@"正在初始化游戏配置,即将进入游戏"},

{11001,@"无需消耗流量、无解压"},
{11002,@"无需消耗流量、无解压"},
{11003,@"无需消耗流量、无解压"},
{11004,@"无需消耗流量、无解压"},
{11005,@"无需消耗流量、无解压{0:F}%"},
{11006,@"无需消耗流量、无解压{0}/{1} 文件数{2}/{3} {4}/s"},
{11007,@"无需消耗流量、无解压"},

{11206,@"确定"},
{11207,@"取消"},

{11301,@"提示"},
{11302,"<color=red>当前没有可使用的网络,请连接正确的网络4G/Wifi!</color>\n<color=#00800BFF>连接网络后将自动继续</color>"},
{11303,"<color=red>文件下载发生异常!\n<size=25><color=#00800BFF>可以尝试重试或是重启游戏修复</color></size>\n<size=12>{0}</size></color>"},
{11304,@"再试一把"},
{11305,@"重试"},
{11306,"资源检查发生异常!\n<color=red><size=12>{0}</size></color>\n请点击【重试】进行重新加载\n<color=#00800BFF><size=22>(若多次重试无效,请联系客服)</size></color>"},
{11307,@"获取资源地址失败,请联系客服!是否重试?"},

{12000,@"声音组件初始化失败!"},
{12001,@"材质组件初始化失败!"},
};

public static string GetLanguage(int id)
{
if (HmlPHPData.IsIosVerify())
{
return s_IOSLanguage.ContainsKey(id) ? s_IOSLanguage[id] : id.ToString();
}
else
{
return s_UpdateLanguage.ContainsKey(id) ? s_UpdateLanguage[id] : id.ToString();
}
}
}
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;

public class UpdateUtility
{
//解析版本文件
public static XVersionFile DeVersion(AssetBundle assetBundle, string path)
{
XVersionFile version = null;
TextAsset textAsset = assetBundle.LoadAsset<TextAsset>("version");
if (textAsset == null || string.IsNullOrEmpty(textAsset.text))
{
XLogger.ERROR(string.Format("LaunchUpdate::CheckVersion() 版本文件损坏 ! path={0}", path));
}
else
{
version = JsonUtility.FromJson<XVersionFile>(textAsset.text);
Debug.Log(textAsset.text);
Resources.UnloadAsset(textAsset);
}

assetBundle.Unload(true);
return version;
}

public static XVersionFile DeVersion(string data, string path)
{
XVersionFile version = null;
version = JsonUtility.FromJson<XVersionFile>(data);
return version;
}

public static XAssetsFiles DeFileList(string data)
{
XAssetsFiles assetFiles = null;
assetFiles = JsonUtility.FromJson<XAssetsFiles>(data);
return assetFiles;
}

public static string ReadAssetList(AssetBundle ab)
{
if (ab == null)
return null;

string data = string.Empty;
if (ab != null)
{
TextAsset textAsset = ab.LoadAsset<TextAsset>(ab.GetAllAssetNames()[0]);
if (textAsset != null)
{
data = textAsset.text;
Resources.UnloadAsset(textAsset);
}
ab.Unload(true);
}
return data;
}

public static string GetVersionStrInfo(XVersionFile version)
{
return string.Format("Dev:{0}|{1} Art:{2}|{3} files:{4} manifest:{5}",
version.p_DevVersion.svnVer, version.p_DevVersion.buildDate,
version.p_ArtVersion.svnVer, version.p_ArtVersion.buildDate,
version.p_files_md5, version.p_manifest_md5);
}


//初始化Dll
public static void InitDll()
{
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_STANDALONE_WIN)
string path = "00/00000000000000000000000000000001.asset";
path = Path.Combine(AssetManagement.AssetDefine.ExternalSDCardsPath, path);
if (File.Exists(path))
{
try
{
AssetBundle ab = AssetBundle.LoadFromFile(path);
TextAsset[] texts = ab.LoadAllAssets<TextAsset>();

string dllPath = AssetManagement.AssetDefine.DataDataPath;

#if UNITY_STANDALONE_WIN
dllPath = Path.Combine(dllPath, "Managed");
#endif

foreach (var text in texts)
{
string savePath = Path.Combine(dllPath, string.Format("{0}.dll", text.name));
XFileUtility.WriteBytes(savePath, text.bytes);
Resources.UnloadAsset(text);
}
ab.Unload(true);
XMobileUtility.RestartApplication();
}
catch (System.Exception e)
{
XLogger.ERROR(string.Format("UpdateUtility::InitDll error:{0}", e.ToString()));
}
}
#endif
}

public static string ReadBuildinAssetList(string path)
{
string error = string.Empty;
return ReadAssetList(XFileUtility.ReadStreamingAssetBundle(path, out error));
}


public static void SetUIVersionInfo(XVersionFile local, XVersionFile server)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Art {0}", Application.version);
if (local != null)
{
sb.AppendFormat(".{0}", local.p_ArtVersion.svnVer);
if (server != null && server.p_ArtVersion.svnVer != local.p_ArtVersion.svnVer)
sb.AppendFormat("<color=#00ff00> - {0}</color>", server.p_ArtVersion.svnVer);
}

sb.Append("\n");

sb.AppendFormat("Dev {0}", Application.version);
if (local != null)
{
sb.AppendFormat(".{0}", local.p_DevVersion.svnVer);
if (server != null && server.p_DevVersion.svnVer != local.p_DevVersion.svnVer)
sb.AppendFormat("<color=#00ff00> - {0}</color>", server.p_DevVersion.svnVer);
}

DefaultLoaderGUI.SetVerText(sb.ToString());
}

public static void ShowTextTip(string str)
{
SystemTipGUI.ShowTip(str);
}
}