using Game.Config;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
class LocalFilePathInfo
{
public string Path;
///
/// 是否可读可写文件夹
///
public bool IsLocalRW;
public LocalFilePathInfo()
{
Path = "";
IsLocalRW = false;
}
public LocalFilePathInfo(string path,bool rw)
{
Path = path;
IsLocalRW = rw;
}
}
public class DownloadMgr : Singleton
{
public const int TimeOut = 60;
private string downloadBaseUrl;
private string downloadUrl;
public string DownloadUrl { get => downloadUrl; }
private int downloadTaskMaxNum;
public int DownloadTaskMaxNum { get => downloadTaskMaxNum; }
private string localFilePath;
public string LocalFilePath { get => localFilePath; }
private List needDownloadList;
private Dictionary downloadingList;
private List downloadSucessList;
private List remoteResList;
private Dictionary localResMap;
private Dictionary remoteResMap;
private bool isInited = false;
private GameDataFormatInfo downloadFormatInfo;
private string versionFileName;
private string assetsFileName;
private string downloadedAssetsFileName;
private ulong downloadSize;
private ulong downloadingSize;
public ulong DownloadSize { get => downloadSize + GetDownloadingSize(); }
private ulong totalSize;//总大小
public ulong TotalSize { get => totalSize; }
public bool CheckFinish { get;private set; }
public bool DowmloadError { get; private set; }
//private byte[] versionData;
//private byte[] mainfestData;
private string versionData;
//private UnityWebRequest mainfestData;
private int tryGetVersionCount;
public bool isQiangDownload;
public string ResVersion { get; private set; }
public override void Init()
{
InitField();
}
private ulong GetDownloadingSize()
{
downloadingSize = 0;
foreach (var item in downloadingList)
{
downloadingSize += item.Value;
}
return downloadingSize;
}
private string GetIOSDownloadPath()
{
return "res/IosRes/";
//#if GAME_DEBUG
//#else
//#endif
}
private string GetAndroidDownloadPath()
{
#if GAME_ONE
return "res/WDAndroidRes/";
#elif GAME_DEBUG
return "res/TestServerRes/";
#else
return "res/WDAndroidRes/";
#endif
}
private string GetDownloadBaseUrl()
{
#if GAME_ONE
return "http://101.43.46.101:88/";
#elif CN_I7GAME_ZHUAN
return "http://43.248.186.74:88/";
#elif CN_I7GAME_0_1
return "http://103.239.245.64:88/"; // "http://weix.vvfyj.cn/";//
#elif GAME_DEBUG
return "http://110.40.223.119:88/";
#else
#if UNITY_EDITOR
return "http://43.248.187.68:88/";
#else
return "http://cdn.yishanyou.com:88/";
#endif
#endif
}
private string GetBaseUrl()
{
#if GAME_ONE
return "";//"http://101.43.46.101:81/";
#elif CN_I7GAME_ZHUAN
return "http://43.248.186.74:81/";
#elif CN_I7GAME_0_1
return "http://103.239.245.64:81/";
#elif GAME_DEBUG
return "";//"http://110.40.223.119:81/";
#else
#if UNITY_EDITOR
return "";//"http://43.248.187.68:81/";
#else
return ""//"http://cdn.yishanyou.com:81/";
#endif
#endif
}
private string GetDownloadUrl()
{
#if UNITY_IOS
return GetDownloadBaseUrl() + GetIOSDownloadPath();
#else
return GetDownloadBaseUrl() + GetAndroidDownloadPath();
#endif
}
private string GetDownloadUrlFormServer(string baseUrl)
{
#if UNITY_IOS
return baseUrl + GetIOSDownloadPath();
#else
return baseUrl + GetAndroidDownloadPath();
#endif
}
private void InitField()
{
if (!isInited)
{
downloadUrl = GetDownloadUrl();
downloadTaskMaxNum = 5;
localFilePath = GetLocalResPath();//FileSystem.LocalDocumentPath;
versionFileName = "Version";
assetsFileName = "mainfest";
downloadedAssetsFileName = "downloaded";
needDownloadList = new List(100);
downloadSucessList = new List(100);
downloadingList = new Dictionary(downloadTaskMaxNum);
remoteResList = new List(1024);
localResMap = new Dictionary(1024);
remoteResMap = new Dictionary(1024);
isInited = true;
CheckFinish = false;
DowmloadError = false;
downloadSize = 0;
downloadingSize = 0;
totalSize = 0;
tryGetVersionCount = 0;
isQiangDownload = true;
ResVersion = "0.0.0.0";
}
}
//
private string GetPlatform()
{
#if UNITY_EDITOR
return "IOS";// "PC";
#else
#if UNITY_IOS
return "IOS";//
#else
return "Android";//
#endif
#endif
}
public void CheckVersion()
{
string baseUrl = GetBaseUrl();
if (!string.IsNullOrEmpty(baseUrl) && tryGetVersionCount <= 3)
{
baseUrl += $"serverlist/download?platform={GetPlatform()}";
AssetDownloader.Instance.DownLoadFileByCoroutine(baseUrl,webReq=>
{
if (webReq == null)
{
CheckFinish = true;
DowmloadError = true;
return;
}
string url = webReq.downloadHandler.text;
url = url.Substring(1, url.Length - 2);
if (url.IndexOf("http://") < 0)
{
url = "http://"+ url;
}
Debug.Log("请求得到:" + url);
downloadUrl = GetDownloadUrlFormServer(url + "/");
StartCheck();
});
}
else
{
downloadUrl = GetDownloadUrl();
StartCheck();
}
}
private void StartCheck()
{
ReadDataFromFile(versionFileName, lVdatas =>
{
if (lVdatas!= null)
{
ResVersion = Encoding.UTF8.GetString(lVdatas);
}
AssetDownloader.Instance.DownLoadFileByCoroutine(GetRemoteUrl(versionFileName), webRqst =>
{
tryGetVersionCount++;
if (webRqst == null)
{
SetCheckFinishAddDownError();
return;
}
byte[] data = webRqst.downloadHandler.data;
string version = Encoding.UTF8.GetString(data);
Debug.Log("服务器 version = " + version);
versionData = version;
OnloadedLocalVersion(lVdatas, version);
});
}, true);
}
public void DownLoadRemoteRes()
{
int size = needDownloadList.Count;
int downsize = downloadSucessList.Count;
downloadSize = 0;
totalSize = 0;
for (int i = 0; i < size; i++)
{
if (needDownloadList[i].FullName == "Version")
{
needDownloadList[i].State = DownloadTaskState.DownloadSuccess;
continue;
}
totalSize += needDownloadList[i].Size;
DownloadDataEntity entity = downloadSucessList.FindFirst(it=>it.FullName == needDownloadList[i].FullName);
if (downsize > 0 && entity != null && entity.MD5 == needDownloadList[i].MD5)
{
needDownloadList[i].State = DownloadTaskState.DownloadSuccess;
downloadSize += needDownloadList[i].Size;
}
else
{
needDownloadList[i].Callback = DownloadedCallback;
needDownloadList[i].UpDateCallback = DownloadedUpdateCallback;
AssetDownloader.Instance.AddDownloadTask(needDownloadList[i]);
}
}
}
public bool DownLoadFinish()
{
bool ret = true;
int size = needDownloadList.Count;
for (int i = 0; i < size; i++)
{
if (needDownloadList[i].State != DownloadTaskState.DownloadSuccess)
{
ret = false;
}
}
return ret || DowmloadError || !AssetDownloader.Instance.HasTask();
}
public bool CheckNeedDownload()
{
return downloadSize < totalSize;
}
private void DownloadedUpdateCallback(DownloadTask task)
{
if (task == null)
{
// DowmloadError = true;
//AssetDownloader.Instance.CancelDownLoad = true;
return;
}
Log($"下载:{task.downloadSize}/{task.CurDownloadEntity.Size} 进度:{task.CurLoadProgress*100}%");
//downloadingSize = task.downloadSize;
if (!downloadingList.ContainsKey(task.CurDownloadEntity))
{
downloadingList.Add(task.CurDownloadEntity, task.downloadSize);
}
else
{
downloadingList[task.CurDownloadEntity] = task.downloadSize;
}
}
public void Log(string str)
{
#if UNITY_EDITOR
Debug.Log(str);
#endif
}
private void DownloadedCallback(DownloadTask task)
{
if (task == null || task.State == DownloadTaskState.Error)
{
//DowmloadError = true;
//AssetDownloader.Instance.CancelDownLoad = true;
if (task != null &&task.CurDownloadEntity.DownloadErrCount >= 3)
{
task.CurDownloadEntity.Url = GetDownloadUrl() + task.CurDownloadEntity.FullName;
Log("重新设置Url = " + task.CurDownloadEntity.Url);
}
else if (task != null && task.CurDownloadEntity.DownloadErrCount >= 10)
{
DowmloadError = true;
}
return;
}
DownloadDataEntity entity = downloadSucessList.FindFirst(it => it.FullName == task.CurDownloadEntity.FullName);
if (entity != null)
{
entity.MD5 = task.CurDownloadEntity.MD5;
entity.Size = task.CurDownloadEntity.Size;
}
else
{
downloadSucessList.Add(task.CurDownloadEntity);
}
if (downloadingList.ContainsKey(task.CurDownloadEntity))
{
downloadingList.Remove(task.CurDownloadEntity);
}
downloadingSize = 0;
downloadSize += task.downloadSize;
string savepath = localFilePath + downloadedAssetsFileName;
CsvWriter csvWriter = new CsvWriter(savepath, "", downloadSucessList, downloadFormatInfo);
csvWriter.Write();
}
private List SerizlizeResList(byte[] data)
{
CsvReader csvReader = new CsvReader(FileHelper.GetName(assetsFileName), data);
if (downloadFormatInfo == null)
{
downloadFormatInfo = new GameDataFormatInfo(csvReader.Fields(), csvReader.Types());
}
Type type = typeof(DownloadDataEntity);
MethodInfo methodInfo = type.GetMethod("OnCsvLoad", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
methodInfo?.Invoke(null, new object[] { csvReader });
List resList = DownloadDataEntity.AllData();
DownloadDataEntity.Clear();
return resList;
}
private void GetRemoteResList()
{
string remoteversionpath = downloadUrl + assetsFileName;
AssetDownloader.Instance.DownLoadFileByCoroutine(remoteversionpath, webRqst =>
{
if (webRqst == null)
{
SetCheckFinishAddDownError();
return;
}
byte[] data = webRqst.downloadHandler.data;
// mainfestData = new byte[data.Length];
// data.CopyTo(mainfestData,0);
//mainfestData = webRqst;
List reResList = SerizlizeResList(data);
if (reResList != null)
{
OnRomoteListDownloaded(reResList);
}
});
}
private void OnRomoteListDownloaded(List downloadDatas)
{
remoteResList.AddRange(downloadDatas);
int size = downloadDatas.Count;
for (int i = 0; i < size; i++)
{
remoteResMap.Add(downloadDatas[i].FullName, downloadDatas[i]);
}
//#if UNITY_IOS
// ReadDataFromFile(assetsFileName, OnloadedLocalResList, false, 1);
//#else
// ReadDataFromFile(assetsFileName, OnloadedLocalResList);
//#endif
ReadDataFromFile(assetsFileName, OnloadedLocalResList);
}
//uint major
//uint minor
//uint release
//uint patch
private void SetCheckFinish()
{
versionData = null;
CheckFinish = true;
}
private void SetCheckFinishAddDownError()
{
if (isQiangDownload && tryGetVersionCount <= 10)
{
CheckVersion();
}
else
{
CheckFinish = true;
DowmloadError = true;
}
}
private string GetLocalResPath()
{
string localPath = FileSystem.LocalDocumentPath;
//#if UNITY_IOS
// localPath = "file://" + localPath;
//#endif
return localPath;
}
private string GetStreamResPath()
{
string streamPath = FileSystem.LocalPackagePath;
#if UNITY_IOS
streamPath = "file://" + streamPath;
#endif
return streamPath;
}
private void OnloadedLocalVersion(byte[] datas, string version)
{
string lVersionstr = "0.0.0.0";
if (datas != null)
{
lVersionstr = Encoding.UTF8.GetString(datas);
}
VersionCode lVersionCode = lVersionstr;//本地 local version
VersionCode RVersionCode = version;// 远端 version
string streamPath = GetStreamResPath();
AssetDownloader.Instance.AssetLoadByCorutine(streamPath + versionFileName, filedatas =>
{
if (filedatas == null)
{
GetRemoteResList();
Debug.Log("====== SVersionstr 为空 =====");
return;
}
VersionCode SVersionCode;// stream data version
string SVersionstr = Encoding.UTF8.GetString(filedatas);
SVersionCode = SVersionstr;
VersionCode localMaxCode = lVersionCode > SVersionCode ? lVersionCode : SVersionCode;
ResVersion = localMaxCode;
if (localMaxCode == RVersionCode)
{
Debug.Log($"lVersionstr = {lVersionstr} SVersionstr = {SVersionstr} ===== version = {version} 不需要更新");
SetCheckFinish();
return;
}
if (localMaxCode >= RVersionCode && SVersionCode == localMaxCode)
{
Debug.Log($"lVersionstr = {lVersionstr} SVersionstr = {SVersionstr} ===== version = {version} 不需要跟新 需要删除之前下载资源");
versionData = null;
ReadDataFromFile(downloadedAssetsFileName, dlocaldatas =>
{
if (dlocaldatas != null)
{
List localdownloadedList = SerizlizeResList(dlocaldatas);
if (localdownloadedList != null && localdownloadedList.Count > 0)
{
downloadSucessList.AddRange(localdownloadedList);
}
DeleteDownloadFiles();
}
else
{
SetCheckFinish();
}
},true);
}
else
{
Debug.Log($"lVersionstr = {lVersionstr} SVersionstr = {SVersionstr} ===== version = {version} 需要更新");
GetRemoteResList();
//CheckFinish = true;
}
});
}
private void OnloadedVersion(byte[] datas,string version)
{
if (datas == null)
{
GetRemoteResList();
Debug.Log("====== data 为空 =====");
}
else
{
string lVersionstr = Encoding.UTF8.GetString(datas);
Debug.Log($"lVersionstr = {lVersionstr} ===== version = {version} ");
if (lVersionstr == version)
{
Debug.Log($"lVersionstr = {lVersionstr} ===== version = {version} 不需要更新");
SetCheckFinish();
return;
}
else
{
VersionCode lVersionCode = lVersionstr;//本地 local version
VersionCode RVersionCode = version;// 远端 version
if (RVersionCode < lVersionCode)
{
SetCheckFinish();
}
else if (RVersionCode.major > lVersionCode.major || (RVersionCode.major == lVersionCode.major && RVersionCode.minor > lVersionCode.minor))
{
AssetDownloader.Instance.AssetLoadByCorutine(GetStreamResPath() + versionFileName, filedatas =>
{
VersionCode SVersionCode;// stream data version
string SVersionstr = Encoding.UTF8.GetString(filedatas);
SVersionCode = SVersionstr;
if (SVersionCode >= RVersionCode && SVersionCode >= lVersionCode)
{
Debug.Log($"lVersionstr = {SVersionstr} ===== version = {version} 重新安装后需要删除之前资源");
versionData = null;
ReadDataFromFile(downloadedAssetsFileName, dlocaldatas=>
{
if (dlocaldatas != null)
{
List localdownloadedList = SerizlizeResList(dlocaldatas);
if (localdownloadedList != null && localdownloadedList.Count > 0)
{
downloadSucessList.AddRange(localdownloadedList);
}
DeleteDownloadFiles();
}
});
}
else
{
Debug.Log($"lVersionstr = {lVersionstr} ===== version = {version} 需要更新");
GetRemoteResList();
//CheckFinish = true;
}
});
}
else if (RVersionCode.release > lVersionCode.release || (RVersionCode.release == lVersionCode.release && RVersionCode.patch > lVersionCode.patch))
{
Debug.Log($"lVersionstr = {lVersionstr} ===== version = {version} 需要更新");
GetRemoteResList();
}
else
{
SetCheckFinish();
}
}
}
}
private void OnloadedLocalResList(byte[] datas)
{
if (datas == null)
{
}
else
{
List localList = SerizlizeResList(datas);
if (localList != null)
{
int size = localList.Count;
for (int i = 0; i < size; i++)
{
localResMap.Add(localList[i].FullName, localList[i]);
}
}
}
ReadDataFromFile(downloadedAssetsFileName, OnloadedDownloadResList);
}
private void OnloadedDownloadResList(byte[] datas)
{
if (datas != null)
{
List localdownloadedList = SerizlizeResList(datas);
if (localdownloadedList != null && localdownloadedList.Count > 0)
{
downloadSucessList.AddRange(localdownloadedList);
}
}
GetNeedDownloadlist();
DownLoadRemoteRes();
}
private List GetLoacalResList(string path)
{
List resList = null;
if (System.IO.File.Exists(path))
{
byte[] data = System.IO.File.ReadAllBytes(path);
resList = SerizlizeResList(data);
}
return resList;
}
private void GetNeedDownloadlist()
{
string ver = "Version";
if (localResMap.ContainsKey(ver) && remoteResMap.ContainsKey(ver)&& localResMap[ver].MD5 == remoteResMap[ver].MD5)
{
Debug.Log("版本为最新状态");
SetCheckFinish();
//string savepath = localFilePath + downloadedAssetsFileName;
//FileHelper.DeleteFile(savepath);
return;
}
if (localResMap == null || localResMap.Count <= 0)
{
foreach (var item in remoteResMap)
{
needDownloadList.Add(item.Value);
}
}
else
{
foreach (var item in remoteResMap)
{
if (item.Key == ver)
{
continue;
}
if (!localResMap.ContainsKey(item.Key) || localResMap[item.Key].MD5 != item.Value.MD5)
{
Debug.Log($"需跟新文件:{item.Value.FullName}");
needDownloadList.Add(item.Value);
}
}
}
CheckFinish = true;
}
private string GetRemoteUrl( string name)
{
return downloadUrl + name;
}
private LocalFilePathInfo GetLocalFilePath(string name, bool onlyLocal = false, uint streamPerPath = 0)
{
LocalFilePathInfo ret = new LocalFilePathInfo();
string path = LocalFilePath + name;
ret.IsLocalRW = true;
if (!FileSystem.Exists(path))
{
Debug.Log($" ========= LocalFilePath Path = {path} 不存在");
if (!onlyLocal)
{
string lpPath = GetStreamResPath();
for (int i = 0; i < streamPerPath; i++)
{
lpPath += "../";
}
path = lpPath + name;
}
ret.IsLocalRW = false;
}
ret.Path = path;
Debug.Log($" ========= local Path = {path} ");
return ret;
}
private void ReadDataFromFile(string name,Action callback,bool onlyLocal = false,uint streamPerPath = 0)
{
LocalFilePathInfo dlocalPath = GetLocalFilePath(name,onlyLocal, streamPerPath);
if (dlocalPath.IsLocalRW)
{
try
{
byte[] dlocaldatas = File.ReadAllBytes(dlocalPath.Path);
callback?.Invoke(dlocaldatas);
}
catch
{
Debug.Log("读取失败" + dlocalPath.Path);
callback?.Invoke(null);
}
}
else if(onlyLocal)
{
callback?.Invoke(null);
}
else
{
AssetDownloader.Instance.AssetLoadByCorutine(dlocalPath.Path, callback);
}
}
private IEnumerator DeleteFiles()
{
;
int length = downloadSucessList.Count;
string savepath = null;
for (int i = 0; i < length; i++)
{
if (downloadSucessList[i].FullName == "font.unity3d")
{
Debug.Log("跳过删除");
continue;
}
savepath = localFilePath + downloadSucessList[i].FullName;
Debug.Log(savepath);
FileHelper.DeleteFile(savepath);
yield return null;
}
FileHelper.DeleteFile(localFilePath + downloadedAssetsFileName);
yield return null;
FileHelper.DeleteFile(localFilePath + versionFileName);
yield return null;
FileHelper.DeleteFile(LocalFilePath + assetsFileName);
yield return null;
SetCheckFinish();
}
public void DeleteDownloadFiles()
{
AssetDownloader.Instance.DoByCorutine(DeleteFiles);
}
public void Free()
{
if (!DowmloadError)
{
if (!string.IsNullOrEmpty(versionData))
{
FileHelper.WirteStringToFile(localFilePath + versionFileName, versionData);
ResVersion = versionData;
}
if (remoteResList.Count > 0)
{
CsvWriter csvWriter = new CsvWriter(LocalFilePath + assetsFileName, "", remoteResList, downloadFormatInfo);
csvWriter.Write();
}
}
needDownloadList = null;
downloadSucessList = null;
remoteResList = null;
localResMap = null;
remoteResMap = null;
versionData = null;
//mainfestData = null;
AssetDownloader.Instance.ClearTasks();
}
}