Loader
This commit is contained in:
ALEXTANG
2022-06-27 11:40:03 +08:00
parent cc37fa374b
commit 234a265362
3 changed files with 604 additions and 0 deletions

View File

@@ -22,5 +22,40 @@ namespace TEngine
public class LoadData
{
public UpdateType Type; //是否底包更新
public UpdateStyle Style; //是否强制更新
public UpdateNotice Notice;//是否提示
public List<LoadResource> List;
public List<LoadResource> All;
}
public enum UpdateType
{
None = 0,
PackageUpdate = 1, //底包更新
ResourceUpdate = 2,//资源更新
}
public enum UpdateStyle
{
None = 0,
Froce = 1, //强制
Optional = 2,//非强制
}
public enum UpdateNotice
{
None = 0,
Notice = 1, //提示
NoNotice = 2,//非提示
}
public enum VersionRequestErrorCode
{
Ok = 1,
Error = 2,
Invalid_Param = 3,
Update_Process = 4,
Patch_Not_Exist = 5
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace TEngine
{
@@ -35,6 +37,9 @@ namespace TEngine
private const int MaxTryCount = 3;
private bool _connectBack;
private bool _needUpdate = false;
private LoadData _currentData;
private UpdateType _currentType = UpdateType.None;
private readonly string _downloadFilePath = FileSystem.ResourceRoot + "/";
public LoadMgr()
{
@@ -93,6 +98,244 @@ namespace TEngine
{
}
try
{
var onlineParamStr = LoaderUtilities.HttpGet(OnlineParamUrl);
var onlineParam = (Dictionary<string, object>)MiniJSON.Json.Deserialize(onlineParamStr);
string onlineResVersion = onlineParam["resVersion"].ToString();
TLogger.LogInfo($"onlineResVersion:{onlineResVersion}");
LatestResId = onlineResVersion;
var resListStr = LoaderUtilities.HttpGet(GetOnlineResListUrl(LatestResId) + "Md5CheckList.json");
var resDic = (Dictionary<string, object>)MiniJSON.Json.Deserialize(resListStr);
List<object> resList = (List<object>)resDic["target"];
_connectBack = true;
OnHttpResponse(CreateLoadData(onlineParam, resList));
}
catch (Exception e)
{
#if UNITY_EDITOR
StartGame();
#else
LoaderUtilities.DelayFun(RequestVersion, new WaitForSeconds(1f));
#endif
TLogger.LogError(e.Message);
}
return;
}
internal void OnHttpResponse(LoadData formatData)
{
if (formatData == null)
{
return;
}
//检测一下是不是本地存在该版本,如果存在就本地做回退,不需要走下载流程
_currentData = formatData;
var exitLocalVersion = _CheckLocalVersion(_currentData.List);
if (exitLocalVersion)
{
_needUpdate = LatestResId != GameConfig.Instance.ResId;
StartGame();
return;
}
//检测一下本地是否存在资源,如果存在了就直接解压就行了,如果不存在还需要下载
_currentData.List = _CheckLocalExitResource(_currentData.List);
_currentType = _currentData.Type;
//TODO
}
/// <summary>
/// 本地检测,过滤掉本地存在了的资源
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
private List<LoadResource> _CheckLocalExitResource(List<LoadResource> res)
{
var list = new List<LoadResource>();
foreach (var item in res)
{
string resPath = _downloadFilePath + item.Url;
if (File.Exists(resPath))
{
if (string.CompareOrdinal(LoaderUtilities.GetMd5Hash(resPath), item.Md5) == 0)
{
continue;
}
list.Add(item);
}
else
{
list.Add(item);
}
}
return list;
}
/// <summary>
/// 检测是否是版本回退了
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
private bool _CheckLocalVersion(List<LoadResource> res)
{
foreach (var item in res)
{
string tempVersion = item.Url.Split('_')[1];
if (!GameConfig.Instance.CheckLocalVersion(tempVersion))
{
return false;
}
}
return true;
}
void StartGame()
{
if (_startGameEvent != null)
{
_startGameEvent();
}
}
internal LoadData CreateLoadData(Dictionary<string, object> onlineParam, List<object> resList = null)
{
if (onlineParam == null)
{
return null;
}
var data = new LoadData();
var result = int.Parse("1");
var versionStr = LoaderUtilities.HttpGet(GetOnlineResListUrl(LatestResId) + "version.json");
var versionDic = (Dictionary<string, object>)MiniJSON.Json.Deserialize(versionStr);
string version = versionDic["AppVersion"].ToString();
switch (result)
{
case (int)VersionRequestErrorCode.Ok:
{
data.Type = UpdateType.ResourceUpdate;
data.Style = UpdateStyle.Optional;
data.Notice = UpdateNotice.Notice;
data.Type = (UpdateType)int.Parse(onlineParam["UpdateType"].ToString());
if (GameConfig.Instance.ResId == LatestResId)
{
TLogger.LogInfo("GameConfig.Instance.ResId 匹配,无需更新");
data.Type = UpdateType.None;
}
if (data.Type != UpdateType.PackageUpdate)
{
data.Style = (UpdateStyle)int.Parse(onlineParam["UpdateStyle"].ToString());
data.Notice = (UpdateNotice)int.Parse(onlineParam["UpdateNotice"].ToString());
}
data.List = new List<LoadResource>();
data.All = new List<LoadResource>();
if (resList != null)
{
for (int i = 0; i < resList.Count; i++)
{
var item = (Dictionary<string, object>)resList[i];
string fileName = item["fileName"].ToString();
var itemTemp = new LoadResource
{
RemoteUrl = _onlineResListUrl + fileName,
Md5 = item["md5"].ToString(),
Size = (long)item["fileSize"],
Url = fileName + "_" + LatestResId,
};
data.List.Add(itemTemp);
data.All.Add(itemTemp);
}
}
break;
}
case (int)VersionRequestErrorCode.Patch_Not_Exist:
LatestResId = string.Empty;
#if UNITY_EDITOR_WIN || _DEVELOPMENT_BUILD_
StartGame();
#else
//TODO
#endif
return null;
default:
return null;
}
if (GameConfig.Instance.ResId == LatestResId)
{
TLogger.LogInfo($"GameConfig.Instance.ResId{GameConfig.Instance.ResId} == onlineResVersion{LatestResId}");
}
else
{
TLogger.LogInfo($"GameConfig.Instance.ResId{GameConfig.Instance.ResId} != onlineResVersion{LatestResId}");
}
return data;
}
private string _resListUrl = string.Empty;
private string _onlineParamUrl = string.Empty;
internal const string Url = "http://1.12.241.46:8081/TXYXGame/";
internal string ResListUrl
{
get
{
if (string.IsNullOrEmpty(_resListUrl))
{
#if UNITY_EDITOR || UNITY_ANDROID
_resListUrl = Url + "AssetBundles/Android/ver_" + GameConfig.Instance.ResId + "/";
#elif UNITY_IOS || UNITY_IPHONE
_resListUrl = Url + "AssetBundles/IOS/ver_" + GameConfig.Instance.ResId + "/";
#elif UNITY_STANDALONE_WIN
_resListUrl = Url + "AssetBundles/WIN/ver_" + GameConfig.Instance.ResId + "/";
#endif
}
return _resListUrl;
}
}
private string _onlineResListUrl = string.Empty;
internal string GetOnlineResListUrl(string onlineResId)
{
if (string.IsNullOrEmpty(_onlineResListUrl))
{
#if UNITY_EDITOR || UNITY_ANDROID
_onlineResListUrl = Url + "AssetBundles/Android/ver_" + onlineResId + "/";
#elif UNITY_IOS || UNITY_IPHONE
_onlineResListUrl = Url + "AssetBundles/IOS/ver_" + onlineResId + "/";
#elif UNITY_STANDALONE_WIN
_onlineResListUrl = Url + "AssetBundles/WIN/ver_" + onlineResId + "/";
#endif
}
TLogger.LogInfo(_onlineResListUrl);
return _onlineResListUrl;
}
internal string OnlineParamUrl
{
get
{
if (string.IsNullOrEmpty(_onlineParamUrl))
{
#if UNITY_EDITOR || UNITY_ANDROID
_onlineParamUrl = Url + "androidVer.json";
#elif UNITY_IOS || UNITY_IPHONE
_onlineParamUrl = Url + "iosVer.json";
#elif UNITY_STANDALONE_WIN
_onlineParamUrl = Url + "winVer.json";
#endif
}
return _onlineParamUrl;
}
}
}
}

View File

@@ -1,10 +1,14 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace TEngine
{
@@ -63,5 +67,327 @@ namespace TEngine
return string.Empty;
}
}
#region WebRequest
public class NetContent
{
public bool Statue;
public bool Result;
public string MsgContent;
public byte[] data;
public Action<bool, string> SuccessCallback;
public Action<bool, string> ErrorCallback;
public void SetResult(bool result, string content)
{
Statue = true;
Result = result;
MsgContent = content;
}
public void SetParam(byte[] param)
{
data = param;
}
public void SetAction(Action<bool, string> success, Action<bool, string> faile)
{
SuccessCallback = success;
ErrorCallback = faile;
}
public void Clear()
{
Statue = false;
Result = false;
MsgContent = "";
}
}
private static NetContent _msgContent = new NetContent();
private static Coroutine _coroutine;
private static HttpWebRequest webReq;
/// <summary>
/// 网络请求
/// </summary>
/// <param name="postUrl"></param>
/// <param name="paramData"></param>
/// <param name="dataEncode"></param>
/// <param name="msgId"></param>
/// <param name="appid"></param>
/// <param name="appSecret"></param>
/// <param name="successCallback"></param>
/// <param name="errorCallback"></param>
public static void PostWebRequest(
string postUrl,
string paramData,
Action<bool, string> successCallback = null,
Action<bool, string> errorCallback = null
)
{
TLogger.LogInfo($"TEngine.LoaderUtilities.PostWebRequest url:{postUrl},paramData:{paramData}");
_msgContent.Clear();
byte[] byteArray = Encoding.UTF8.GetBytes(paramData);
if (webReq != null)
{
webReq.Abort();
webReq = null;
GC.Collect();
}
webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));
webReq.Method = "POST";
webReq.ContentType = "application/json";
webReq.ContentLength = byteArray.Length;
_msgContent.SetParam(byteArray);
_msgContent.SetAction(successCallback, errorCallback);
var result = webReq.BeginGetRequestStream(RequestComplete, webReq);
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, TimeoutCallback, result, 2000, true);
if (_coroutine != null)
{
MonoManager.Instance.StopCoroutine(_coroutine);
}
_coroutine = MonoManager.Instance.StartCoroutine(_Response(_msgContent));
}
private static IEnumerator _Response(NetContent content)
{
while (content.Statue == false)
{
yield return null;
}
if (content.Result)
{
_msgContent.SuccessCallback?.Invoke(content.Result, content.MsgContent);
}
else
{
_msgContent.ErrorCallback?.Invoke(content.Result, "");
}
if (_coroutine != null)
{
MonoManager.Instance.StopCoroutine(_coroutine);
_coroutine = null;
}
}
private static void RequestComplete(IAsyncResult result)
{
if (result != null && result.IsCompleted)
{
var request = result.AsyncState as HttpWebRequest;
try
{
Stream stream = request.EndGetRequestStream(result);
stream.Write(_msgContent.data, 0, _msgContent.data.Length);
stream.Close();
stream.Dispose();
var rspResult = webReq.BeginGetResponse(ResponseComplete, webReq);
ThreadPool.RegisterWaitForSingleObject(rspResult.AsyncWaitHandle, TimeoutCallback, result, 2000, true);
}
catch (Exception e)
{
_msgContent.SetResult(false, e.ToString());
throw;
}
}
}
private static void ResponseComplete(IAsyncResult asyncResult)
{
HttpWebRequest request;
HttpWebResponse response;
StreamReader reader;
Stream recive;
request = (asyncResult.AsyncState as HttpWebRequest);
var res = request.EndGetResponse(asyncResult);
response = res as HttpWebResponse;
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
recive = response.GetResponseStream();
reader = new StreamReader(recive);
try
{
string result = reader.ReadToEnd();
_msgContent.SetResult(true, result);
reader.Close();
reader.Dispose();
recive.Close();
recive.Dispose();
response.Close();
request.Abort();
}
catch (Exception e)
{
_msgContent.SetResult(false, e.ToString());
throw;
}
finally
{
if (reader != null)
{
reader.Close();
reader.Dispose();
}
if (request != null)
{
reader.Dispose();
}
if (response != null)
{
response.Close();
}
if (request != null)
{
request.Abort();
}
}
}
else
{
if (response == null)
{
_msgContent.SetResult(false, "HttpResponse:response is null");
}
else
{
_msgContent.SetResult(false, "HttpResponse:" + response.StatusCode.ToString());
}
}
}
private static void TimeoutCallback(object state, bool timedOut)
{
if (!timedOut) return;
_msgContent.SetResult(false, "timeout");
IAsyncResult result = state as IAsyncResult;
if (result != null)
{
try
{
Stream stream = webReq.EndGetRequestStream(result);
stream.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
webReq.Abort();
}
}
/// <summary>
/// 延迟执行
/// </summary>
/// <param name="callback"></param>
/// <param name="time"></param>
public static Coroutine DelayFun(Action callback, YieldInstruction time)
{
return MonoManager.Instance.StartCoroutine(DelayFunIEnumerator(callback, time));
}
public static IEnumerator DelayFunIEnumerator(Action callback, YieldInstruction time)
{
yield return time;
callback();
}
#endregion
/// <summary>
/// 数据格式转换
/// </summary>
/// <param name="data">数据</param>
/// <returns></returns>
public static string FormatData(long data)
{
string result = "";
if (data < 0)
data = 0;
if (data > 1024 * 1024)
{
result = ((int)(data / (1024 * 1024))).ToString() + "MB";
}
else if (data > 1024)
{
result = ((int)(data / 1024)).ToString() + "KB";
}
else
{
result = data + "B";
}
return result;
}
/// <summary>
/// 获取文件大小
/// </summary>
/// <param name="path">文件路径</param>
/// <returns></returns>
public static long GetFileSize(string path)
{
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return file.Length;
}
return 0;
}
/// <summary>
/// GET请求与获取结果
/// </summary>
public static string HttpGet(string url, string postDataStr = "")
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + (postDataStr == "" ? "" : "?") + postDataStr);
request.Method = "GET";
request.ContentType = "text/html;charset=UTF-8";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream myResponseStream = response.GetResponseStream();
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);
string retString = myStreamReader.ReadToEnd();
myStreamReader.Close();
myResponseStream.Close();
return retString;
}
/// <summary>
/// POST请求与获取结果
/// </summary>
public static string HttpPost(string url, string postDataStr)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postDataStr.Length;
StreamWriter writer = new StreamWriter(request.GetRequestStream(), Encoding.ASCII);
writer.Write(postDataStr);
writer.Flush();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string encoding = response.ContentEncoding;
if (encoding == null || encoding.Length < 1)
{
encoding = "UTF-8"; //默认编码
}
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding));
string retString = reader.ReadToEnd();
return retString;
}
}
}