Files
tianrunCRM/Assets/CoolapeFrame/Scripts/resMgr/CLVerManager.cs
2020-07-04 14:41:25 +08:00

688 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
********************************************************************************
*Copyright(C),coolae.net
*Author: chenbin
*Version: 2.0
*Date: 2017-01-09
*Description: 热更新处理(处理部分移到lua里了)
*Others:
*History:
*********************************************************************************
*/
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using UnityEngine.Networking;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Coolape
{
public class CLVerManager : CLBaseLua
{
public bool isPrintDownload = false;
public int downLoadTimes4Failed = 3;
//服务器
public string baseUrl = "http://your hot fix url";
[HideInInspector]
public string platform = "";
public static CLVerManager self;
public static string resVer = "resVer";
public static string versPath = "VerCtl";
public const string fverVer = "VerCtl.ver";
//========================
//本地所有版本的版本信息
public const string verPriority = "priority.ver";
public Hashtable localPriorityVer = new Hashtable();
//本地优先更新资源
public const string verOthers = "other.ver";
public Hashtable otherResVerOld = new Hashtable();
//所有资源的版本管理
public Hashtable otherResVerNew = new Hashtable();
//所有资源的版本管理
public bool haveUpgrade = false;
public bool is2GNetUpgrade = false;
public bool is3GNetUpgrade = true;
public bool is4GNetUpgrade = true;
[HideInInspector]
public string mVerverPath = "";
[HideInInspector]
public string mVerPrioriPath = "";
[HideInInspector]
public string mVerOtherPath = "";
static string clientVersionPath
{
get
{
return Path.Combine(CLPathCfg.persistentDataPath, "ver.v"); //客户端版本
}
}
public CLVerManager()
{
self = this;
}
public string clientVersion
{
get
{
try
{
if (!File.Exists(clientVersionPath))
{
return "";
}
return File.ReadAllText(clientVersionPath);
}
catch (System.Exception e)
{
return "";
}
}
set
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(clientVersionPath));
File.WriteAllText(clientVersionPath, value);
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
}
// 用文件来表示是否已经处理完资源从包里释放出来的状态
static string hadPoc
{
get
{
return Path.Combine(CLPathCfg.persistentDataPath, "resPoced");
}
}
Callback onFinisInitStreaming;
/// <summary>
/// Inits the streaming assets packge.
/// 将流目录中优先需要加载的资源集解压到可读写目录
/// </summary>
/// <param name="onFinisInitStreaming">On finis init streaming.</param>
public void initStreamingAssetsPackge(Callback onFinisInitStreaming)
{
this.onFinisInitStreaming = onFinisInitStreaming;
// clean cache
#if UNITY_EDITOR
if (CLCfgBase.self.isEditMode)
{
onFinisInitStreaming();
return;
}
#endif
try
{
// 当版本不同时, clean cache
if (string.Compare(Application.version, clientVersion) != 0)
{
string path = Application.persistentDataPath;
// 先删掉目录下的文件
string[] fEntries = Directory.GetFiles(path);
foreach (string f in fEntries)
{
File.Delete(f);
}
// 再删掉所有文件夹
string[] dirEntries = Directory.GetDirectories(path);
foreach (string dir in dirEntries)
{
Directory.Delete(dir, true);
}
clientVersion = Application.version;
}
// 处理资源释放
if (!File.Exists(hadPoc))
{
string path = "priority.r";
Callback cb = onGetStreamingAssets;
StartCoroutine(FileEx.readNewAllBytesAsyn(path, cb));
}
else
{
onFinisInitStreaming();
}
}
catch (System.Exception e)
{
Debug.LogError(e);
onFinisInitStreaming();
}
}
// 取得"priority.r"
void onGetStreamingAssets(params object[] para)
{
if (para != null && para.Length > 0)
{
byte[] buffer = (byte[])(para[0]);
if (buffer != null)
{
MemoryStream ms = new MemoryStream();
ms.Write(buffer, 0, buffer.Length);
ms.Position = 0;
object obj = B2InputStream.readObject(ms);
if (obj != null)
{
Hashtable map = (Hashtable)(obj);
string path = "";
foreach (DictionaryEntry cell in map)
{
try
{
path = CLPathCfg.persistentDataPath + "/" + cell.Key;
Directory.CreateDirectory(Path.GetDirectoryName(path));
File.WriteAllBytes(path, (byte[])(cell.Value));
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
// 处理完包的资源释放,弄个标志
Directory.CreateDirectory(Path.GetDirectoryName(hadPoc));
File.WriteAllText(hadPoc, "ok");
}
}
}
Utl.doCallback(onFinisInitStreaming);
}
public Hashtable toMap(byte[] buffer)
{
Hashtable r = new Hashtable();
if (buffer != null)
{
MemoryStream ms = new MemoryStream();
ms.Write(buffer, 0, buffer.Length);
ms.Position = 0;
object obj = B2InputStream.readObject(ms);
if (obj != null && obj is Hashtable)
{
r = (Hashtable)obj;
}
else
{
r = new Hashtable();
}
}
else
{
r = new Hashtable();
}
return r;
}
//================================================================
public static Hashtable wwwMap = Hashtable.Synchronized(new Hashtable());
//public static Hashtable wwwTimesMap = new Hashtable();
/// <summary>
/// Gets the newest res.取得最新的资源
/// </summary>
/// <param name='path'>
/// Path.资源的相对路径
/// </param>
/// <param name='type'>
/// Type.资源的类型
/// </param>
/// <param name='onGetAsset'>
/// On get asset.取得资源后的回调(回调信息中:
/// 第一个参数是资源路径,
/// 第二参数是资源的内容,
/// 第三个参数传入的原样返回的参数)
/// </param>
/// <param name='originals'>
/// Originals.原样返回的参数
/// </param>
public void getNewestRes4Lua(string path, CLAssetType type, object onGetAsset, bool autoRealseAB, object originals)
{
getNewestRes(path, type, onGetAsset, autoRealseAB, originals);
}
public void getNewestRes(string path, CLAssetType type, object onGetAsset, bool autoRealseAB, params object[] originals)
{
if (string.IsNullOrEmpty(path))
{
return;
}
string verVal = "";
if (!MapEx.getBool(wwwMap, path))
{
string url = "";
bool needSave = false;
wwwMap[path] = true;
#if UNITY_WEBGL
if (!CLCfgBase.self.isEditMode)
{
if (localPriorityVer[path] != null)
{
verVal = MapEx.getString(localPriorityVer, path);
}
else
{
verVal = MapEx.getString(otherResVerNew, path);
}
if (!string.IsNullOrEmpty(verVal))
{
url = PStr.begin().a(baseUrl).a("/").a(path).a(".").a(verVal).end();
}
else
{
url = PStr.begin().a(baseUrl).a("/").a(path).end();
}
doGetContent(path, url, needSave, type, onGetAsset, autoRealseAB, originals);
return;
}
#endif
if (localPriorityVer[path] != null)
{
//在优先资源里有
needSave = false;
}
else
{
//则可能在others里
object obj1 = otherResVerOld[path];
object obj2 = otherResVerNew[path];
if (obj1 == null && obj2 != null)
{ //本地没有,最新有
verVal = MapEx.getString(otherResVerNew, path);
needSave = true;
}
else if (obj1 != null && obj2 != null)
{
if (obj1.ToString().Equals(obj2.ToString()))
{//本地是最新的
needSave = false;
}
else
{ //本地不是最新的
verVal = MapEx.getString(otherResVerNew, path);
needSave = true;
}
}
else if (obj1 != null && obj2 == null)
{//本地有,最新没有
needSave = false;
}
else
{ //都没有找到
needSave = false;
#if UNITY_EDITOR
// Debug.LogWarning ("Not found.path==" + path);
#endif
}
}
if (needSave)
{
if (!string.IsNullOrEmpty(verVal))
{
url = PStr.begin().a(baseUrl).a("/").a(path).a(".").a(verVal).end();
}
else
{
url = PStr.begin().a(baseUrl).a("/").a(path).end();
}
if (isPrintDownload)
{
Debug.LogWarning(url);
}
}
else
{
url = PStr.begin().a(CLPathCfg.persistentDataPath).a("/").a(path).end();
if (!File.Exists(url))
{
url = System.IO.Path.Combine(Application.streamingAssetsPath, path);
#if !UNITY_ANDROID || UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
#if UNITY_STANDALONE
url = PStr.begin ().a ("file:///").a (url).end ();
#else
url = PStr.begin().a("file://").a(url).end();
#endif
#endif
}
else
{
#if UNITY_STANDALONE
url = PStr.begin ().a ("file:///").a (url).end ();
#else
url = PStr.begin().a("file://").a(url).end();
#endif
}
}
doGetContent(path, url, needSave, type, onGetAsset, autoRealseAB, originals);
}
}
void doGetContent(string path, string url, bool needSave,
CLAssetType type, object onGetAsset, bool autoRealseAB, params object[] originals)
{
#if UNITY_EDITOR
getedResMap[path] = true;
#endif
if (url.StartsWith("http"))
{
url = url.Replace("+", "%2B");
}
wwwMap[path] = true;
NewList transParam = ObjPool.listPool.borrowObject();
transParam.Add(path);
transParam.Add(url);
transParam.Add(needSave);
transParam.Add(type);
transParam.Add(onGetAsset);
transParam.Add(originals);
transParam.Add(autoRealseAB);
UnityWebRequest www = null;
if (needSave)
{
#if UNITY_EDITOR
Debug.LogWarning(url);
#endif
CLAssetType tmptype = type;
if (type == CLAssetType.assetBundle)
{
//因为通过DownloadHandlerAssetBundle无法取得bytes所以只能先改变取得数据类型然后再通过AssetBundle.LoadFromMemory取得AssetBundle
tmptype = CLAssetType.bytes;
}
www = WWWEx.get(url, tmptype, (Callback)onWWWBack, (Callback)onWWWBack, transParam, true, downLoadTimes4Failed);
addWWW(www, path, url);
}
else
{
www = WWWEx.get(url, type, (Callback)onWWWBack, (Callback)onWWWBack, transParam, true);
}
}
void onWWWBack(params object[] parma)
{
try
{
object content = parma[0];
NewList list = parma[1] as NewList;
string path = list[0] as string;
string url = list[1] as string;
bool needSave = (bool)(list[2]);
CLAssetType type = (CLAssetType)(list[3]);
object onGetAsset = list[4];
object[] originals = list[5] as object[];
bool autoRealseAB = (bool)(list[6]);
UnityWebRequest www = null;
if (parma.Length > 2)
{
www = parma[2] as UnityWebRequest;
}
if (needSave && www != null && www.downloadHandler.data != null)
{
saveNewRes(path, www.downloadHandler.data);
if (type == CLAssetType.assetBundle)
{
content = AssetBundle.LoadFromMemory(www.downloadHandler.data);
}
}
onGetNewstRes(www, url, path, type, content, needSave, onGetAsset, autoRealseAB, originals);
ObjPool.listPool.returnObject(list);
list = null;
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
public void onGetNewstRes(UnityWebRequest www, string url, string path, CLAssetType type, object content, bool needSave, object onGetAsset, bool autoRealseAB, params object[] originals)
{
try
{
if (needSave)
{
//说明是需要下载的资源
//if (www != null && content == null && (MapEx.getInt(wwwTimesMap, path) + 1) < downLoadTimes4Failed)
//{
// //需要下载资源时,如查下载失败,且少于失败次数,则再次下载
// wwwTimesMap[path] = MapEx.getInt(wwwTimesMap, path) + 1;
// doGetContent(path, url, needSave, type, onGetAsset, autoRealseAB, originals);
// return;
//}
rmWWW(url);
}
if (content == null)
{
Debug.LogError("get newstRes is null. url==" + url);
}
Utl.doCallback(onGetAsset, path, content, originals);
if (autoRealseAB && content != null && type == CLAssetType.assetBundle)
{
AssetBundle ab = content as AssetBundle;
if (ab != null)
{
ab.Unload(false);
}
}
}
catch (System.Exception e)
{
Debug.LogError(e + "\n" + path);
}
if (www != null)
{
www.Dispose();
www = null;
}
wwwMap[path] = false;
//wwwTimesMap[path] = 0;
}
object addWWWcb;
object rmWWWcb;
public void setWWWListner(object addWWWcb, object rmWWWcb)
{
this.addWWWcb = addWWWcb;
this.rmWWWcb = rmWWWcb;
}
public void addWWW(UnityWebRequest www, string path, string url)
{
Utl.doCallback(addWWWcb, www, path, url);
}
public void rmWWW(string url)
{
Utl.doCallback(rmWWWcb, url);
}
/// <summary>
/// Saves the new res.保存最新取得的资源
/// </summary>
/// <param name='path'>
/// Path.
/// </param>
/// <param name='content'>
/// Content.
/// </param>
void saveNewRes(string path, byte[] content)
{
string file = PStr.begin().a(CLPathCfg.persistentDataPath).a("/").a(path).end();
Directory.CreateDirectory(Path.GetDirectoryName(file));
File.WriteAllBytes(file, content);
if (otherResVerNew[path] != null)
{ //优先更新资源已经是最新的了,所以不用再同步
otherResVerOld[path] = otherResVerNew[path];
MemoryStream ms = new MemoryStream();
B2OutputStream.writeMap(ms, otherResVerOld);
string vpath = PStr.begin().a(CLPathCfg.persistentDataPath).a("/").a(mVerOtherPath).end();
Directory.CreateDirectory(Path.GetDirectoryName(vpath));
File.WriteAllBytes(vpath, ms.ToArray());
}
}
public Texture getAtalsTexture4Edit(string path)
{
string url = "";
#if UNITY_EDITOR
url = "file://" + Application.dataPath + "/" + path;
#endif
WWW www = new WWW(Utl.urlAddTimes(url));
while (!www.isDone)
{
// new WaitForSeconds (0.05f);
System.Threading.Thread.Sleep(50); //比较hacker的做法
}
if (string.IsNullOrEmpty(www.error))
{
Texture texture = www.texture;
www.Dispose();
www = null;
return texture;
}
else
{
www.Dispose();
www = null;
return null;
}
}
public bool checkNeedDownload(string path)
{
if (string.IsNullOrEmpty(path))
{
return false;
}
bool ret = false;
if (localPriorityVer[path] != null)
{ //在优先资源里有
ret = false;
}
else
{ //则可能在others里
object obj1 = otherResVerOld[path];
object obj2 = otherResVerNew[path];
if (obj1 == null && obj2 != null)
{ //本地没有,最新有
ret = true;
}
else if (obj1 != null && obj2 != null)
{
if (NumEx.stringToInt(obj1.ToString()) >= NumEx.stringToInt(obj2.ToString()))
{//本地是最新的
ret = false;
}
else
{ //本地不是最新的
ret = true;
}
}
else if (obj1 != null && obj2 == null)
{//本地有,最新没有
ret = false;
}
else
{ //都没有找到
// NAlertTxt.add("Cannot Found the res. Path= \n"+ path, Color.red, 1);
Debug.LogError("Cannot Found the res. Path= \n" + path);
ret = true;
}
}
// if (ret) {
// if (!Utl.netIsActived ()) {
// NAlertTxt.add (Localization.Get ("MsgNetWorkCannotReached"), Color.red, 1);
// reLoadGame ();
// }
// }
return ret;
}
/// <summary>
/// Ises the ver newest.
/// </summary>
/// <returns>
/// The ver newest.
/// </returns>
/// <param name='path'>
/// If set to <c>true</c> path.
/// </param>
/// <param name='ver'>
/// If set to <c>true</c> ver.
/// </param>
public bool isVerNewest(string path, string ver)
{
object newVer = localPriorityVer[path];
if (newVer != null)
{ //在优先资源里有
if (!ver.Equals(newVer.ToString()))
{
return false;
}
return true;
}
else
{ //则可能在others里
newVer = otherResVerNew[path];
if (newVer != null)
{
if (!ver.Equals(newVer.ToString()))
{
return false;
}
return true;
}
return true;
}
}
Hashtable getedResMap = new Hashtable();
[ContextMenu("save loaded assets(with out priority assets)")]
public void getCurrentRes()
{
#if UNITY_EDITOR
string str = "";
foreach (DictionaryEntry cell in getedResMap)
{
str += cell.Key + "," + "true" + "\n";
}
Debug.LogError(str);
string path = EditorUtility.SaveFilePanelInProject("save loaded assets(with out priority assets)", "newAssetsInfor", "v", "");
if (!string.IsNullOrEmpty(path))
{
File.WriteAllText(path, str);
}
#endif
}
}
}