游戏内容变更之后。一般而言不会想让玩家下载整个游戏包又一次安装,由于这样会流失大量玩家。全部游戏更新是必须的。

更新的内容包含 数据、资源、代码。

基本原理:

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 自己主动文件更新系统的更多相关文章

  1. 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)

    1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...

  2. 制作SD更新系统时和用mfgtool工具烧录时,文件如何替换?

    制作SD更新系统时和用mfgtool工具烧录时,文件如何替换? 答:制作SD更新系统时,请按照需求选择不同mfgimages-myd*文件夹.每个文件夹里面有一个Manifest文件, 里面规定了ub ...

  3. CentOS更改yum源与更新系统

    [1] 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...

  4. CentOS 更改yum源与更新系统

    FROM:http://www.cnblogs.com/lightnear/archive/2012/10/03/2710952.html [1] 首先备份/etc/yum.repos.d/CentO ...

  5. [转]CentOS更改yum源与更新系统

    [1] 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...

  6. 引擎设计跟踪(九.9) 文件包系统(Game Package System)

    很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...

  7. CentOS 7更改yum源与更新系统

    在CentOS 7下更改yum源与更新系统. [1] 首先备份/etc/yum.repos.d/CentOS-Base.repo cp /etc/yum.repos.d/CentOS-Base.rep ...

  8. MAC EI Capitan上更新系统自带SVN版本号(关闭SIP方能sudo rm)

    继昨晚之后.决定更新系统自带的svn.自带的svn版本号是1.7.看官网svn:http://www.wandisco.com/subversion/download#osx 最新版本号是1.9.13 ...

  9. expect脚本同步文件 expect脚本指定host和要同步的文件 构建文件分发系统 批量远程执行命令

    自动同步文件 #!/usr/bin/expect set " spawn rsync -av root@.txt /tmp/ expect { "yes/no" { se ...

随机推荐

  1. 解决utf8' codec can't decode byte 0xe5 in position 0: unexpected end of data

    使用unicode对象的话,除了这样使用u标记,还可以使用unicode类以及字符串的encode和decode方法. unicode类的构造函数接受一个字符串参数和一个编码参数,将字符串封装为一个u ...

  2. 使用剩余参数代替 arguments (prefer-rest-params)

    使用剩余参数代替 arguments (prefer-rest-params) 剩余参数来自于ES2016.可以在可变函数中使用这个特性来替代arguments变量. arguments没有Array ...

  3. 【BZOJ 1305】[CQOI2009]dance跳舞

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 男生和女生每个人都分身成两个节点 即x[1],x[2]和y[1],y[2] 然后如果i和j不相互喜欢 那么add(x[i][2],y ...

  4. 2015 Multi-University Training Contest 7 hdu 5373 The shortest problem

    The shortest problem Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  5. 工具-VS使用GIT工具

    由于VS中集成了GIT插件,本机安装了GIT工具和TortoiseGit工具,造成在VS中GIT无法同步,于是将TortoiseGit卸载,再次启用VS中的GIT插件,重新初始化GIT文件夹,问题解决 ...

  6. iOS 手势识别器概述

    手势识别器 iOS 手势识别器(UIGestureRecognizer) 点击手势(UITapGestureRecognizer) 滑动手势(UISwipeGestureRecognizer) 旋转手 ...

  7. mysql数据库连接工具类C3P0

    package com.dl.network_flow.db; import java.sql.Connection; import java.sql.PreparedStatement; impor ...

  8. 【Linux驱动】TQ2440 DM9000E网卡驱动移植(Linux-2.6.30.4)

    花了一天的时间研究了一下Linux-2.6.30.4版本号内核下关于TQ2440 DM9000E的网卡驱动移植.总结一下自己的收获. 事实上.在Linux-2.6.30.4版本号内核下有关于网卡驱动, ...

  9. zzulioj--1790-- 弹珠游戏(数学水题!)

    弹珠游戏 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 14  Solved: 10 SubmitStatusWeb Board Descriptio ...

  10. Oracle 10g RAC (linux) ASM 共享存储的管理详解

    ---------ASM 的管理(共享磁盘的管理)1.以 instance 的方式管理 ASM,启动 database 之前必须先启动 ASM instance,ASM instance 启动后,挂载 ...