/*
********************************************************************************
*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;
///
/// Inits the streaming assets packge.
/// 将流目录中优先需要加载的资源集解压到可读写目录
///
/// On finis init streaming.
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();
///
/// Gets the newest res.取得最新的资源
///
///
/// Path.资源的相对路径
///
///
/// Type.资源的类型
///
///
/// On get asset.取得资源后的回调(回调信息中:
/// 第一个参数是资源路径,
/// 第二参数是资源的内容,
/// 第三个参数传入的原样返回的参数)
///
///
/// Originals.原样返回的参数
///
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);
}
///
/// Saves the new res.保存最新取得的资源
///
///
/// Path.
///
///
/// Content.
///
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;
}
///
/// Ises the ver newest.
///
///
/// The ver newest.
///
///
/// If set to true path.
///
///
/// If set to true ver.
///
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
}
}
}