unity3d 自动文件更新系统

unity3d 自动文件更新系统

时间 2014-08-27 17:47:10  CSDN博客原文  http://blog.csdn.net/x_studying/article/details/38873727

游戏内容变更之后,一般而言不会想让玩家下载整个游戏包重新安装,因为这样会流失大量玩家。所有游戏更新是必须的。更新的内容包括 数据、资源、代码。

基本原理:

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.需要一个资源更新服务器,将导出的AssetBundle文件和crc文件上传到资源更新服务器。可以用一个简单的http服务器。例如nginx。

3.客户端进入游戏之前,首先向更新服务器请求crc.txt文件。然后从本地的磁盘目录中查找crc.txt文件,检查需要更新的文件列表。然后从服务器下载需要更新的文件。这样,如果服务器没有更改文件,则只需要下载一次。

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);

}

时间: 2024-10-15 06:16:19

unity3d 自动文件更新系统的相关文章

web服务文件更新自动同步、数据库主从复制、shell脚本实现网站代码备份和mysql备份

基搭建LAMP环境,并实践基于DNS做基于域名的虚拟主机中的环境,重新搭建一个同样的环境 要求: a)实现web服务文件更新的自动同步到另一台机器上 b)数据库实现主从复制 c)通过shell脚本实现网站源代码备份和mysql备份,备份策略包括全量备份.增量备份.差异备份 a,实现web服务文件更新的自动同步到另一台机器上: 1,在httpd服务器上建立基于FQDN的两个虚拟web站点,并创建相关目录. 2,修改测试windows主机的hosts文件,并编辑两个虚拟web站点对应的目录下的ind

Unity3D 自动打包整个项目(以AssetBundle实现)

原地址:http://blog.csdn.net/huang7jiao/article/details/18370653 需求: 在移动开发中,手动控制资源的加载.释放和热更新,是很有必要的. 而Unity通过AssetBundle可以实现该需求,但是如果项目资源多起来的话一个个手动打包成AssetBundle则很麻烦. 而本文正为此提供一套一键打包的方案. 资源分类.加载和实例化过程: 分类资源: 先将游戏资源分类,这里说的分类不是按资源类型(声音.贴图等)来分,而是按照打包进同一个Asset

2.2-构建简易文件分发系统

构建文件分发系统 1. 需求背景 对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台.所以,自动同步文件是至关重要的. 2. 实现思路 首先要有一台模板机器,把要分发的文件准备好,然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可.注意:环境必须一致,否则可能出现问题. 3. 核心命令 rsync -av --files-from=list.txt  /  [email protected]:/     这条语句用来批量

20.31 expect脚本同步文件;20.32 expect脚本指定host和要同步的文件;20.33 构建文件分发系统;20.34

20.31 expect脚本同步文件 自动同步文件 1. 同步远程机器hao2上/tmp/12.txt文件 到本机/tmp/下: [[email protected] ~]# vim 4.expect 添加内容: #!/usr/bin/expect set passwd "admin" spawn rsync -av [email protected]192.168.211.129:/tmp/12.txt /tmp/ expect { "yes/no" { send

Unity3D之Legacy动画系统学习笔记

Unity3D的Mecanim动画系统是非常强大的,而且作为Unity推荐的动画系统,其未来会完全代替老的一套动画系统,即Legacy动画系统.目前的情况是Mecanim与Legacy两套动画系统同时共存,但是并不是说Legacy动画系统就没有任何价值了,作为Unity4.0以前使用的动画系统,我认为还是很有必要去了解和学习的,所以就有了这篇笔记. Legacy动画系统 http://docs.unity3d.com/Manual/Animations.html 我们可以使用Unity自带的资源

解决Unity3d 4.3 动画系统带来的烦恼

近期有非常多同学问我关于unity3d 4.3更新之后动画系统和曾经不一样了,并且之前用的非常熟练的创建动画和修修改画非常多操作都不好用了,那么在这里和大家分享一下三杀的个人经验,方便大家使用unity3d 4.3的动画系统. 首先,我们要明白知道的一点是Unity3d 是逐步的将老的动画系统删除,取而代之的是新的动画系统叫做Mecanim.所以就会出现变来变去,越变越不好用的情况,只是等到Unity3d把旧版动画系统全然删除的时候,一个崭新的动画系统就会展如今我们眼前,期待是这样吧. (下面内

shell(构建文件分发系统)

1. 需求背景对于大公司而言,肯定时不时会有网站或者配置文件更新,而且使用的机器肯定也是好多台,少则几台,多则几十甚至上百台.所以,自动同步文件是至关重要的. 2. 实现思路首先要有一台模板机器,把要分发的文件准备好,然后只要使用expect脚本批量把需要同步的文件分发到目标机器即可.3. 核心命令rsync -av --files-from=list.txt  /  [email protected]:/4. 文件分发系统的实现vim  rsync.expect #!/usr/bin/expe

[原]Unity3D深入浅出 - 新版动画系统(Mecanim)

Mecanim概述: Mecanim是Unity提供第一个丰富而复杂的动画系统,提供了: 针对人形角色的简易的工作流和动画创建能力 Retargeting(运动重定向)功能,即把动画从一个角色模型应用到另一个角色模型上的能力. 针对Animations Clips(动画片段)的简易工作流,针对动画片段及他们之间的过度和交互预览能力. 一个用于管理动画间复杂交互作用的可视化窗口. 通过不同逻辑来控制不同身体部位的运动能力. Mecanim工作流: 1.资源导入,这一阶段由美术师或动画师通过三维工具

kali linux-01 更新系统及安装vmtools

一.更新系统 1.1 添加更新源地址 [email protected]:~# vi /etc/apt/sources.list 在文件结尾添加更新源地址,并输入:wq保存 deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contribdeb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib 1.2 更新系统 以下步骤重复执行2