您的位置:首页 > 移动开发 > Unity3D

Unity逻辑热更新

2016-05-17 10:08 337 查看
声明:
原博链接: http://blog.csdn.net/janeky/article/details/17652021 只是把自己研究实践的过程记录下来

先直接上代码:两个类,一个检测资源更新,有更新则下载到本地(ResUpdate),一个是逻辑热更新(LogicUpdate)
一、资源对比更新并下载。
资源是否更新了是通过比对服务器与客户端的 资源版本表: version.txt
该文本文档内容为:


Cube.assetbundle,78a6cd06388449d16aea5f6eae395abf

hotab.assetbundle,7ae97ca818017fcb7879c56d6a350676

Sphere.assetbundle,c58c93cffdc73669e10d3f449e1fa29c

version.txt,f864be607802fcc71b622d7ea5383c8f

 

工具地址:https://github.com/kenro/File_Md5_Generator
public class ResUpdate : MonoBehaviour {
public static readonly string VERSION_FILE="version.txt";
public static readonly string LOCAL_RES_URL="file://"+Application.dataPath+"/Res/";
public static readonly string SERVER_RES_URL = "file:///F:/HotUpdateTest/ab/";
public static readonly string LOCAL_RES_PATH=Application.dataPath+"/Res/";

private Dictionary<string,string> LocalResVersion;
private Dictionary<string,string> ServerResVersion;
private List<string> NeedDownFiles;
private bool NeedUpdateLocalVersionFile = false;

// Use this for initialization
void Start () {

LocalResVersion = new Dictionary<string, string> ();
ServerResVersion = new Dictionary<string, string> ();
NeedDownFiles = new List<string> ();

//加载本地version配置
StartCoroutine(DownLoad(LOCAL_RES_URL + VERSION_FILE,
delegate(WWW localVersion)
{
//保存本地的version
ParseVersionFile(localVersion.text, LocalResVersion);
StartCoroutine(DownLoad(SERVER_RES_URL + VERSION_FILE,
delegate(WWW serverVersion)
{
//保存服务端version
ParseVersionFile(serverVersion.text, ServerResVersion);
//对比本地和服务端版本
CompareVersion();
//加载需要更新的资源
DownLoadRes();
}));
}));
}

/// <summary>
/// 保存version
/// </summary>
/// <param name="content"></param>
/// <param name="dict"></param>
private void ParseVersionFile(string content,Dictionary<string,string> dict)
{
if (content==null||content.Length==0)
{
return;
}

string[] items = content.Split(new char[] { '\n' });
foreach (string item in items)
{
string[] info = item.Split(new char[] { ',' });
if (info!=null&&info.Length==2)
{
dict.Add(info[0], info[1]);
}
}
}

/// <summary>
/// 对比本地和服务端版本
/// </summary>
private void CompareVersion()
{
foreach (var version in ServerResVersion)
{
string fileName = version.Key;
string serverMd5 = version.Value;
//新增的资源
if (!LocalResVersion.ContainsKey(fileName))
{
NeedDownFiles.Add(fileName);
}
else
{
//需要替换的资源
string localMd5;
//使用安全的获取方式,即:获取失败就直接替换资源
LocalResVersion.TryGetValue(fileName, out localMd5);
if (!serverMd5.Equals(localMd5))
{
NeedDownFiles.Add(fileName);
}
}
//本次有更新,同时更新本地的version.tex
NeedUpdateLocalVersionFile = NeedDownFiles.Count > 0;
}
}

/// <summary>
/// 加载需要更新的资源
/// </summary>
private void DownLoadRes()
{
if (NeedDownFiles.Count==0)
{
UpdateLocalVersionFile();
return;
}

string file = NeedDownFiles[0];
NeedDownFiles.RemoveAt(0);

StartCoroutine(DownLoad(SERVER_RES_URL + file, delegate(WWW w)
{
//将下载的资源替换本地的资源
ReplaceLocalRes(file, w.bytes);
DownLoadRes();
}));
}

/// <summary>
/// 更新本地的version配置
/// </summary>
private void UpdateLocalVersionFile()
{
if (NeedUpdateLocalVersionFile)
{
StringBuilder versions = new StringBuilder();
foreach (var item in ServerResVersion)
{
versions.Append(item.Key).Append(",").Append(item.Value).Append("\n");
}
FileStream stream = new FileStream(LOCAL_RES_PATH + VERSION_FILE, FileMode.Create);
byte[] data = Encoding.UTF8.GetBytes(versions.ToString());
stream.Write(data, 0, data.Length);
//这里可能是多余的,Flush本来是在没有Close的时候也会
//将缓存中的数据写入到文件中
//但是这里紧接着下面就是Close
stream.Flush();
stream.Close();
}
// 测试用:显示加载的资源包
StartCoroutine(Show());
}

/// <summary>
/// 测试用:显示加载的资源包
/// </summary>
/// <returns></returns>
private IEnumerator Show()
{
WWW asset = new WWW(LOCAL_RES_URL + "Sphere.assetbundle");
yield return asset;
AssetBundle bundle = asset.assetBundle;
Instantiate(bundle.LoadAsset("Sphere"));
///这是U3D没有处理好的一个环节。在WWW加载资源完毕后,对资源进行instantiate后,对其资源进行unload,这时问题就发生 了,instantiate处理渲染需要一定的时间,虽然很短,但也是需要1,2帧的时间。此时进行unload会对资源渲染造成影响,以至于没有贴图或 者等等问题发生。
//解决办法:
//自己写个时间等待代码,最好不要用WaitForSeconds,U3D的API,这个东西很撮,恶心死我了。。。
//我估计它这个类写的有问题,检查了好长时间,最后还是自己写了几行代码来替换这个类,解决了问题。
//等待个0.5秒到1秒之后再进行Unload。这样就不会出现instantiate渲染中就运行unload的情况了。
yield return null;
bundle.Unload(false);
}

/// <summary>
/// 替换本地资源
/// </summary>
/// <param name="fileName"></param>
/// <param name="data"></param>
private void ReplaceLocalRes(string fileName,byte[] data)
{
string filePath = LOCAL_RES_PATH + fileName;
FileStream stream = new FileStream(LOCAL_RES_PATH + fileName, FileMode.Create);
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
}

/// <summary>
/// 加载资源(服务器和本地)
/// </summary>
/// <param name="url"></param>
/// <param name="finishFun"></param>
/// <returns></returns>
private IEnumerator DownLoad(string url,HandleFinishDownload finishFun)
{
using (WWW www = new WWW(url))
{
yield return www;
if (finishFun != null)
{
finishFun(www);
}
}
}

public delegate void HandleFinishDownload(WWW www);
}

二、逻辑热更新
将逻辑代码生成Dll,将其打包成assetbundl前将其后缀改为.bytes,不然会报错


public class LogicUpdate : MonoBehaviour
{
private static readonly string DLL_URL = "file:///D:/HostServer/Blood/AssetBundle/test.assetbundle";

void Start()
{
StartCoroutine(loadDllScript());
}

private IEnumerator loadDllScript()
{
WWW www = new WWW(DLL_URL);
yield return www;
AssetBundle bundle = www.assetBundle;
TextAsset asset = bundle.LoadAsset("test", typeof(TextAsset)) as TextAsset;

System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(asset.bytes);
Type script1 = assembly.GetType("Script");
GameObject obj = new GameObject();
obj.AddComponent(script1);

//Type script2 = assembly.GetType("Script2");
//obj.AddComponent(script2);
}




 
 


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: