unity3d 自己主动文件更新系统
游戏内容变更之后。一般而言不会想让玩家下载整个游戏包又一次安装,由于这样会流失大量玩家。全部游戏更新是必须的。
更新的内容包含 数据、资源、代码。
基本原理:
1、将须要更新的文件打包成AssetBundle文件,并计算各个文件的crc值。
以下代码将选择的文件分别导出为AssetBundle文件,并将每一个文件的crc值写入到crc.txt文件里,在Editor文件夹建立一个类,并复制以下代码。
能够在Project文件夹导出选择的文件。
public class ExportAssetBundles { [MenuItem("Assets/Build AssetBundle From Selection Respective - Track dependencies")] static void ExportResourceRespective() { // Bring up save panel string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d"); string dirpath = path.Substring(0,path.LastIndexOf("/")+1); string filename = path.Substring(path.LastIndexOf("/")+1); if (path.Length != 0) { #if UNITY_ANDROID string targetDir = "Android/"; BuildTarget targetBuild = BuildTarget.Android; #elif UNITY_IPHONE string targetDir = "iPhone/"; BuildTarget targetBuild = BuildTarget.iPhone; #elif UNITY_STANDALONE_WIN string targetDir = "StandaloneWindows/"; BuildTarget targetBuild = BuildTarget.StandaloneWindows; #endif JSDocument.JSNode node = new JSDocument.JSNode("root"); Document.SNode[] nodes = node.putChildren("filehash",Selection.objects.Length); for(int i=0;i<Selection.objects.Length;i++) { string name = Selection.objects[i].name+".unity3d"; uint crc = 0; if(!Directory.Exists(dirpath+targetDir)) Directory.CreateDirectory(dirpath+targetDir); BuildPipeline.BuildAssetBundle(Selection.objects[i],new Object[]{ Selection.objects[i]}, dirpath+targetDir+name,out crc,BuildAssetBundleOptions.CollectDependencies,targetBuild); nodes[i].put("name",name); nodes[i].put("crc",crc); } System.IO.File.WriteAllText(dirpath+targetDir+filename+".crc.txt",node.toJSONString()); } } } |
2.须要一个资源更新server,将导出的AssetBundle文件和crc文件上传到资源更新server。能够用一个简单的httpserver。比如nginx。
3.client进入游戏之前。首先向更新server请求crc.txt文件。然后从本地的磁盘文件夹中查找crc.txt文件,检查须要更新的文件列表。然后从server下载须要更新的文件。这样,假设server没有更改文件,则仅仅须要下载一次。
4.最新的crc.txt文件到本地,以便下次查询。
以下代码演示 3,4 步骤,当中
Engine.Instance.server_datapath = 服务器下载地址。
Engine.Instance.local_datapath = Application.persistentDataPath+"/;
public static IEnumerator UpdateDataFromServer(UpdateProgress up) { string server_datapath = Engine.Instance.server_datapath; string local_datapath = Engine.Instance.local_datapath; byte[] server_crc_data = null; Dictionary<string,long> filehash_server=new Dictionary<string, long>(); Dictionary<string,long> filehash_local=new Dictionary<string, long>(); List<string> needUpdateFile = new List<string>(); Debug.Log("Load Server FileHash"); using(WWW www = new WWW(server_datapath+"crc.txt")) { yield return www; if (!String.IsNullOrEmpty(www.error)) { Debug.Log("Load Filehash Failed"); up(1.0f); yield break; } JSDocument.JSNode node = new JSDocument.JSNode("filehash",www.text); Document.SNode[] data = node.getChildren("filehash"); for(int i=0;i<data.Length;i++) { filehash_server[data[i].get("name","")] = data[i].get("crc",(long)0); } server_crc_data = www.bytes; } Debug.Log("Load Local FileHash"); //从本地载入文件MD5表。可能没有 try { JSDocument.JSNode node = new JSDocument.JSNode("filehash",System.IO.File.ReadAllText(local_datapath+"crc.txt")); Document.SNode[] data = node.getChildren("filehash"); for(int i=0;i<data.Length;i++) { filehash_local[data[i].get("name","")] = data[i].get("crc",(long)0); } } catch(Exception e) { Debug.Log(e.Message); } Debug.Log("Check FileHash"); //计算须要更新的文件 foreach(KeyValuePair<string,long> data in filehash_server) { //更新须要的文件 if(!filehash_local.ContainsKey(data.Key) || filehash_local[data.Key] != data.Value) { needUpdateFile.Add(data.Key); } } Debug.Log("Update File"); //下载并存储 for(int i=0;i<needUpdateFile.Count;i++) { using(WWW www = new WWW(server_datapath+needUpdateFile[i])) { yield return www; byte[] bytes = null; if (!String.IsNullOrEmpty(www.error)) { Debug.Log(www.error); yield break; } else { bytes = www.bytes; } up((float)i/needUpdateFile.Count); string path = local_datapath+ needUpdateFile[i]; Debug.Log(path); FileStream fs = new FileStream(path,FileMode.Create); fs.Write(bytes,0,bytes.Length); fs.Flush(); fs.Close(); // //保存 // BinaryWriter writer; // FileInfo t =new FileInfo(local_datapath+ needUpdateFile[i]); // if(!t.Exists) // { // writer = new BinaryWriter(t.Open(FileMode.OpenOrCreate)); // } // else // { // t.Delete(); // writer = new BinaryWriter(t.Open(FileMode.Create)); // } // writer.Write(bytes); // writer.Close(); } } Debug.Log("Save FileHash"); if(needUpdateFile.Count>0) { //保存最新的文件MD5值表 // FileStream fs = new FileStream(local_datapath+"crc.txt",FileMode.Create); // fs.Write(server_crc_data,0,server_crc_data.Length); // fs.Flush(); // fs.Close(); BinaryWriter writer; FileInfo t =new FileInfo(local_datapath+"crc.txt"); if(!t.Exists) { writer = new BinaryWriter(t.Open(FileMode.Create)); } else { t.Delete(); writer = new BinaryWriter(t.Open(FileMode.Create)); } writer.Write(server_crc_data); writer.Close(); Debug.Log(local_datapath+"crc.txt"); } } |
5.载入已经更新完毕的存储在本地的AssetBundle,须要注意的是。Unity3d同样的文件同一时候仅仅能有一个AssetBundle在内存中,所以我们对于同样文件的载入做了同步。
(loadRefCount)。
static HashSet<string> loadRefCount = new HashSet<string>(); public delegate void delegateLoadFinish(GameObject go); public static IEnumerator LoadModel(string res,delegateLoadFinish onLoadFinish) { GameObject resObject = Resources.Load<GameObject>("cards/"+res); if(resObject !=null) { onLoadFinish((GameObject)GameObject.Instantiate(resObject)); yield break; } //假设包括资源。返回 while(loadRefCount.Contains(res)) { yield return true; } loadRefCount.Add(res); Debug.Log(Engine.Instance.local_datapath+res+".unity3d"); AssetBundleCreateRequest crcLocalBundle = AssetBundle.CreateFromMemory( System.IO.File.ReadAllBytes(Engine.Instance.local_datapath+res+".unity3d")); yield return crcLocalBundle; { GameObject cardObject = GameObject.Instantiate(crcLocalBundle.assetBundle.mainAsset)as GameObject; crcLocalBundle.assetBundle.Unload(false); onLoadFinish(cardObject); } loadRefCount.Remove(res); } |
unity3d 自己主动文件更新系统的更多相关文章
- 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)
1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...
- 制作SD更新系统时和用mfgtool工具烧录时,文件如何替换?
制作SD更新系统时和用mfgtool工具烧录时,文件如何替换? 答:制作SD更新系统时,请按照需求选择不同mfgimages-myd*文件夹.每个文件夹里面有一个Manifest文件, 里面规定了ub ...
- CentOS更改yum源与更新系统
[1] 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...
- CentOS 更改yum源与更新系统
FROM:http://www.cnblogs.com/lightnear/archive/2012/10/03/2710952.html [1] 首先备份/etc/yum.repos.d/CentO ...
- [转]CentOS更改yum源与更新系统
[1] 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...
- 引擎设计跟踪(九.9) 文件包系统(Game Package System)
很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...
- CentOS 7更改yum源与更新系统
在CentOS 7下更改yum源与更新系统. [1] 首先备份/etc/yum.repos.d/CentOS-Base.repo cp /etc/yum.repos.d/CentOS-Base.rep ...
- MAC EI Capitan上更新系统自带SVN版本号(关闭SIP方能sudo rm)
继昨晚之后.决定更新系统自带的svn.自带的svn版本号是1.7.看官网svn:http://www.wandisco.com/subversion/download#osx 最新版本号是1.9.13 ...
- expect脚本同步文件 expect脚本指定host和要同步的文件 构建文件分发系统 批量远程执行命令
自动同步文件 #!/usr/bin/expect set " spawn rsync -av root@.txt /tmp/ expect { "yes/no" { se ...
随机推荐
- WinServer-IIS-URL重写
WEB平台安装程序在Windows Server里面才有,在WIN7里面是没有的 然后在安装一个URL重写工具 然后再设置各种规则 来自为知笔记(Wiz)
- 51 nod 1693 水群
1693 水群 基准时间限制:0.4 秒 空间限制:524288 KB 分值: 160 难度:6级算法题 收藏 关注 总所周知,水群是一件很浪费时间的事,但是其实在水群这件事中,也可以找到一些有 ...
- React-Native系列Android——Native与Javascript通信原理(一)
React-Native最核心的是Native与Javascript之间的通信,并且是双向通信.Native层到Javascript层,Javascript层到Native层.虽说是两个方向,但实现上 ...
- iOS UI08_UITableView
(http://img.blog.csdn.net/20150808103801391) // // MainViewController.m // UI08_UITableView // // Cr ...
- bzoj1816: [Cqoi2010]扑克牌(二分答案判断)
1816: [Cqoi2010]扑克牌 题目:传送门 题解: 被一道毒瘤题搞残了...弃了坑来刷刷水题 一开始还想复杂了...结果发现二分水过: 二分答案...然后check一下,joker肯定尽量用 ...
- Objective-c 中如何重写父类的初始化方法
在我们的日常开发中我们经常会定义一些自己的子类继承一些UIKit 库中的类,那我们应该如何重写的这些初化方法呢?那我们先看看这些类有哪些初初化方法吧.(这里就用UIView为例) - (id)init ...
- 【DNN】 安装问题
http://blog.csdn.net/hwt0101/article/details/9153083 这是IIS 注册的问题 IIS 在安装VS 之前就装上了,所以 没有注册是上 F4 从新卸载 ...
- POJ 3320 Jessica's Reading Problem (尺取法,时间复杂度O(n logn))
题目: 解法:定义左索引和右索引 1.先让右索引往右移,直到得到所有知识点为止: 2.然后让左索引向右移,直到刚刚能够得到所有知识点: 3.用右索引减去左索引更新答案,因为这是满足要求的子串. 4.不 ...
- WCF客户端获取服务端异常[自定义异常]
引言 经过不断的摸索,询问/调试,终于学会了关于WCF客户端与服务端之间异常的处理机制,在此来记录自己的成果,用于记录与分享给需要的伙伴们. 首先感谢[.NET技术群]里群主[轩]的大力帮助,如有需要 ...
- ajax错误信息
XMLHttpRequest.status状态码 1xx-信息提示 这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多个1xx响应. 100-继续. 101-切换协议. 2xx- ...