UNITY4 之bundle依赖打包

/*
* 1. 菜单命令一键打包
* 2. 打包输出目录:StreamAssets/平台/BundleRes400/...
* 3. 依赖保存文件 输出目录/zip/Files.assetBundle.zip
* 4. 打包采用不压缩方式,自己用lzma压缩解压
*/
// 菜单命令 BuildAll 打包 Resources 目录下的所有资源
// 菜单命令 BuildPath 打包 选择目录下 Resources 目录下的所有资源
// 菜单命令 BuildSelFile 打包选择的资源
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Collections;
using System.IO;
using System.Collections.Generic;
using LitJson;
using System.Text;

public class BundleHelper400 : MonoBehaviour
{

	static List<string> buildList = new List<string>();
	static Dictionary<string, string> DicDependencies = new Dictionary<string, string>();

	static Dictionary<string, List<string>> mapDep = new Dictionary<string, List<string>>();

	static List<string> m_listNeedCompress = new List<string>();

	static Dictionary<string, string> mapMd5Files = new Dictionary<string, string>();
#if UNITY_ANDROID
	static string SavePath = Application.streamingAssetsPath + "/Android/BundleRes400/data";
#endif
#if UNITY_IPHONE 
	static string SavePath = Application.streamingAssetsPath + "/IOS/BundleRes400/data";
#endif
#if UNITY_STANDALONE_WIN
     static string SavePath = Application.streamingAssetsPath + "/PC/BundleRes400/data";
#endif

	static string SourcePath = "Assets";

	static string strColletion = "col_";
	static string outFormat = ".assetBundle";

	static int nDependenciesCount = 0;

	static BuildAssetBundleOptions buildOp = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CompleteAssets
	| BuildAssetBundleOptions.DeterministicAssetBundle;
	static BuildOptions opScene = BuildOptions.BuildAdditionalStreamedScenes | BuildOptions.UncompressedAssetBundle;
	static BuildAssetBundleOptions buildOpNoComplete = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.CompleteAssets;
	// 	BuildAssetBundleOptions buildOp = /*(BMDataAccessor.BMConfiger.compress ? 0 : BuildAssetBundleOptions.UncompressedAssetBundle) |*/
	// 					(BMDataAccessor.BMConfiger.deterministicBundle ? 0 : BuildAssetBundleOptions.DeterministicAssetBundle) |
	// 					BuildAssetBundleOptions.CollectDependencies;
#if UNITY_ANDROID
	static BuildTarget target = BuildTarget.Android;
#endif
#if UNITY_IPHONE
#if UNITY_5
		static BuildTarget target = BuildTarget.iOS;
#else
		static BuildTarget target = BuildTarget.iPhone;
#endif
#endif

#if UNITY_STANDALONE_WIN
	static BuildTarget target = BuildTarget.StandaloneWindows;
#endif


	[MenuItem("Assets/Build Assert Bundle 4.0.1/Build All")]
	static void BuildAll()
	{
		Clear();
#if TEST
		BuildPath(SourcePath, buildOp);
#else
		BuildPath(SourcePath + "/Resources", buildOp);
#endif
		string[] path = Directory.GetDirectories(SourcePath + "/Games");
		foreach (var p in path)
		{
#if TEST
			BuildPath(p, buildOp);
#else
			BuildPath(p + "/Resources", buildOp);
#endif
		}
		UpdateDependFile(SavePath);

		LZMPEditHelper.CompressAllFile_(SavePath);
		MD5Tools.GenAllMd5File(SavePath.Replace("/data", "/zip"));
		EditorUtility.DisplayDialog("", "Completed", "OK");
		AssetDatabase.Refresh();
	}

	[MenuItem("Assets/Build Assert Bundle 4.0.1/Build Path")]
	static void BuildPath()
	{
		Clear();
		GetLocalDependFile(SavePath);
		GetLocalMd5File(SavePath);
		string filePath = "";
		Dictionary<string, Object> map = new Dictionary<string, Object>();

		UnityEngine.Object[] arr5 = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets);
		if (arr5 == null || arr5.Length <= 0)
			return;

		foreach (Object obj in arr5)
		{
			filePath = AssetDatabase.GetAssetPath(obj);
			BuildPath(filePath + "/Resources", buildOp);
		}
		UpdateDependFile(SavePath);
		LZMPEditHelper.CompressAllFile_(SavePath);
		MD5Tools.GenAllMd5File(SavePath.Replace("/data", "/zip"));
		EditorUtility.DisplayDialog("", "Completed", "OK");
		AssetDatabase.Refresh();
	}

	[MenuItem("Assets/Build Assert Bundle 4.0.1/Build Sel File")]
	static void BuildSelFile()
	{
		Clear();
		GetLocalDependFile(SavePath);
		GetLocalMd5File(SavePath);
		string filePath = "";
		Dictionary<string, Object> map = new Dictionary<string, Object>();
		foreach (Object obj in Selection.objects)
		{
			filePath = AssetDatabase.GetAssetPath(obj);
			if (filePath.EndsWith(".meta"))
				continue;
			Object p2Asset = AssetDatabase.LoadMainAssetAtPath(filePath);
			//Object[] all = AssetDatabase.LoadAllAssetsAtPath(filePath);
			map[filePath] = p2Asset;
		}
		foreach (var item in map)
		{
			BuildBundle(item.Key, item.Value, buildOp);
		}
		UpdateDependFile(SavePath);
		//LZMPEditHelper.CompressAllFile_(SavePath);
		CompressFiles();
		//MD5Tools.GenAllMd5File(SavePath.Replace("/data", "/zip"));
		EditorUtility.DisplayDialog("", "Completed", "OK");
		AssetDatabase.Refresh();
	}
	[MenuItem("Assets/Build Assert Bundle 4.0.1/Build Scenes")]
	static void BuildScenes()
	{
		Clear();
		GetLocalDependFile(SavePath);
		GetLocalMd5File(SavePath);
		foreach (var item in EditorBuildSettings.scenes)
		{
			if (item.enabled == false)
				continue;
			if (!item.path.Contains("main"))
				BuildBundle(item.path, null, buildOp);
		}
		UpdateDependFile(SavePath);
		CompressFiles();
		//LZMPEditHelper.CompressAllFile_(SavePath);
		MD5Tools.GenAllMd5File(SavePath.Replace("/data", "/zip"));
		EditorUtility.DisplayDialog("", "Completed", "OK");
		AssetDatabase.Refresh();
	}

	static void BuildSceneBundle(string path, Object[] obj, BuildAssetBundleOptions options)
	{
		string[] DependArr = AssetDatabase.GetDependencies(new string[] { path });
		Debug.Log(DependArr[0]);
	}

 
	static void BuildBundle(string[] path, Object[] obj, BuildAssetBundleOptions options)
	{
		for (int i = 0; i < path.Length; i++)
		{
			getMapDep(path[i]);
		}
		refreshMap();

		BuildPipeline.PushAssetDependencies();
		List<string> listTmp = new List<string>();
		BuildBundle_1(path, obj, options, ref listTmp);		
		listTmp.Clear();
		BuildPipeline.PopAssetDependencies();
	}


	static void getMapDep(string path)
	{		
		string[] DependArr = AssetDatabase.GetDependencies(new string[] { path });
		foreach (var item in DependArr)
		{
			string it = item.Replace('\\', '/');
			if (it.EndsWith(".cs"))
				continue;
			if (path.Equals(it))
			{
				continue;
			}
			if (!mapDep.ContainsKey(it))
				mapDep[it] = new List<string>();
			if (!mapDep[it].Contains(path))
				mapDep[it].Add(path);
			string[] childDependArr = AssetDatabase.GetDependencies(new string[] { it });
			if (childDependArr != null && childDependArr.Length > 1 && null == System.Array.Find(new string[] { path }, p => { return p == it; }))
			{
				getMapDep(it);
			}
		}
	}


	static void refreshMap()
	{
		List<string> list_key = new List<string>();
		foreach (var item in mapDep)
		{
			list_key.Add(item.Key);
		}
		foreach (var item in list_key)
			mapDep[item] = refreshList(mapDep[item]);	
	}

	static List<string> refreshList(List<string> list)
	{
		bool isNeedRefresh = false;
		foreach (var item in list)
		{
			for (int i = list.Count - 1; i >= 0; i--)
			{
				if (mapDep.ContainsKey(item) && mapDep[item].Contains(list[i]))
				{
					list.Remove(list[i]);
					isNeedRefresh = true;
				}
			}
			if (isNeedRefresh)
				break;
		}
		if (isNeedRefresh)
			refreshList(list);
		return list;
	}

	static void BuildBundleMapDep(string[] path, Object[] obj, BuildAssetBundleOptions options, ref List<string> listTmp)
	{
		foreach (var item in mapDep)
		{
			BuildPipeline.PushAssetDependencies();

			 // bulid key

			foreach (var list in item.Value)
			{
				BuildPipeline.PushAssetDependencies();

				//BuildBundleMapDep();

				BuildPipeline.PopAssetDependencies();
			}

			BuildPipeline.PopAssetDependencies();
		}
	}

	static void BuildBundle_1(string[] path, Object[] obj, BuildAssetBundleOptions options, ref List<string> listTmp)
	{
		string[] DependArr = AssetDatabase.GetDependencies(path);
		string dependinfo = "";
		
		for (int i = 0; i < DependArr.Length; i++)
		{
			if (!DependArr[i].EndsWith(".cs") && null == System.Array.Find(path, p => { return p == DependArr[i]; }))
			{			
				dependinfo += rePath(DependArr[i]) + ";";
			}				
		}
		if (!string.IsNullOrEmpty(dependinfo))
		{
			DicDependencies[rePath(path[0])] = dependinfo;
		}
			
		foreach (var item in DependArr)
		{
			string it = item.Replace('\\', '/');
			if (it.EndsWith(".cs"))
				continue;
			if (null != System.Array.Find(path, p => { return p == it; }))
			{
				continue;
			}
			//if (buildList.Contains(getFileName(it)))
			//	continue;
			if (listTmp.Contains(getFileName(it)))
				continue;
			string[] childDependArr = AssetDatabase.GetDependencies(new string[] { it });
			if (childDependArr != null && childDependArr.Length > 1 && null == System.Array.Find(path, p => { return p == it; }))
			{
				BuildBundle(new string[] { it }, new Object[] { AssetDatabase.LoadMainAssetAtPath(it) }, options);
				//BuildPipeline.PushAssetDependencies();
				
				continue;
			}

			uint crc = 0;
			bool ret = false;
			if (it.EndsWith(".unity"))
			{
				string re = BuildPipeline.BuildStreamedSceneAssetBundle(new string[] { it }, reNameFile(it), target, out crc, opScene);
				Debug.LogError("BuildSceneAssetBundle error : " + re);
				ret = true;
			}
			else
			{
				Object[] objs = AssetDatabase.LoadAllAssetsAtPath(it);
				ret = BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath(it), objs, reNameFile(it), out crc, options, target);
			}				
			if (ret == false)
			{
				Debug.LogError("BuildAssetBundle error : " + crc.ToString());
				return;
			}
			if (!m_listNeedCompress.Contains(reNameFile(it)))
				m_listNeedCompress.Add(reNameFile(it));
			Debug.Log("BuildAssetBundleEx success: outpath=" + reNameFile(it));
			if (!buildList.Contains(getFileName(it)))
				buildList.Add(getFileName(it));
			listTmp.Add(getFileName(it));
		}
		foreach (var item in path)
		{
			string it = item.Replace('\\', '/');
			//if (buildList.Contains(getFileName(it)))
			//	continue;
			if (listTmp.Contains(getFileName(it)))
				continue;
			uint crc = 0;
			bool ret = false;
			if (it.EndsWith(".unity")) // 场景
			{
				BuildPipeline.BuildStreamedSceneAssetBundle(new string[] { it }, reNameFile(it), target, out crc, opScene);
				ret = true;
			}			
			else
				ret = BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath(it), null, reNameFile(it), out crc, options, target);
			if (ret == false)
			{
				Debug.LogError("BuildAssetBundle error : " + crc.ToString());
				return;
			}
			if (!m_listNeedCompress.Contains(reNameFile(it)))
				m_listNeedCompress.Add(reNameFile(it));
			Debug.Log("BuildAssetBundleEx success: outpath=" + reNameFile(it));
			if (!buildList.Contains(getFileName(it)))
				buildList.Add(getFileName(it));
			listTmp.Add(getFileName(it));
		}		
	}

	static void BuildBundle(string path, Object obj, BuildAssetBundleOptions options)
	{
		BuildBundle(new string[] { path }, new Object[] { obj }, options);
	}

	static void BulidBundle(Dictionary<string, Dictionary<string, Object>> mapRootBundle_, BuildAssetBundleOptions options)
	{
		foreach (var map in mapRootBundle_.Values)
		{
			foreach (var item in map)
			{
				BuildBundle(item.Key, item.Value, options);
			}
		}
	}

	static void BuildPath(string path, BuildAssetBundleOptions options)
	{
		string rootPath = path;
		Dictionary<string, Dictionary<string, Object>> mapRootBundle = new Dictionary<string, Dictionary<string, Object>>();
 		getPathObj(rootPath, ref mapRootBundle);

		BulidBundle(mapRootBundle, options);
		// 打包Base
// 		if (path != SourcePath)
// 		{
// 			string rootPath_ = SourcePath + "/Resources/Base";
// 			Dictionary<string, Dictionary<string, Object>> mapRootBundle_ = new Dictionary<string, Dictionary<string, Object>>();
// 			getPathObj(rootPath_, ref mapRootBundle_);
// 			BulidBundle(mapRootBundle_, options);		
// 		}

// 		string rootPath = path + "/Base";
// 		Dictionary<string, Dictionary<string, Object>> mapRootBundle = new Dictionary<string, Dictionary<string, Object>>();
// 		getPathObj(rootPath, ref mapRootBundle);
// 
// 		BulidBundle(mapRootBundle, options);	
// 		// 打包根目录下资源 // 默认依赖Base
// 		rootPath = path + "/StaticPic"; // 打包Texture
// 		mapRootBundle = new Dictionary<string, Dictionary<string, Object>>();
// 		getPathObj(rootPath, ref mapRootBundle);
// 		BulidBundle(mapRootBundle, options);
// 
// 		// 打包动态资源(没有依赖)
// 		rootPath = path + "/DynamicRes";
// 		mapRootBundle = new Dictionary<string, Dictionary<string, Object>>();
// 		getPathObj(rootPath, ref mapRootBundle);
// 		BulidBundle(mapRootBundle, options);
// 
// 		// 打包prefabs (依赖于base)
// 		rootPath = path + "/Prefabs";
// 		mapRootBundle = new Dictionary<string, Dictionary<string, Object>>();
// 		getPathObj(rootPath, ref mapRootBundle);
// 		BulidBundle(mapRootBundle, options);

	}

	static void getPathObj(string path, ref Dictionary<string, Dictionary<string, Object>> mapBundle)
	{
		if (path != null)
		{
			string[] f1 = null;
			string[] d1 = null;
			try
			{
				f1 = Directory.GetFiles(path, "*");
			}
			catch (System.Exception e)
			{
				Debuger.LogError("GetFiles error : " + e.ToString());
				return;
			}
			Dictionary<string, Object> mapTmp = new Dictionary<string, Object>();
			foreach (string f11 in f1)
			{
				// GUILayout.TextField(f11);
				if (f11.EndsWith(".meta"))
					continue;
				if (target != BuildTarget.StandaloneWindows && f11.Contains("PC"))
					continue;
				else if (target != BuildTarget.Android && f11.Contains("Android"))
					continue;
				else if (target != BuildTarget.iPhone && f11.Contains("IOS"))
					continue;
				Object p2Asset = AssetDatabase.LoadMainAssetAtPath(f11);

				mapTmp[f11.Replace('\\', '/')] = p2Asset;
				Debuger.Log(f11);
			}
			try
			{
				d1 = Directory.GetDirectories(path);
				foreach (string d11 in d1)
				{
					try
					{
						getPathObj(d11, ref mapBundle);
					}
					catch (System.Exception e)
					{
						Debuger.LogError("getPathObj error : " + e.ToString());
						return;
					}
				}
			}
			catch (System.Exception e)
			{
				Debuger.LogError("GetDirectories error : " + e.ToString());
				return;
			}

			if (mapTmp.Count > 0)
			{
				mapBundle[path.Replace('\\', '/')] = mapTmp;
			}
		}
	}
	static string reNameFile(string outpath)
	{

		string ret = outpath;
		ret = ret.Replace('\\', '/');
		if (string.IsNullOrEmpty(ret))
		{
			ret = SavePath;
		}
		else
			ret = ret.Replace(SourcePath, SavePath);
		ret = rePath(ret);
		string path = ret.Substring(0, ret.LastIndexOf('/'));
		if (!Directory.Exists(path))
			Directory.CreateDirectory(path);
		if (!ret.EndsWith(outFormat))
		{
			//ret = ret.Substring(0, ret.LastIndexOf('.'));
			ret += outFormat;
		}
		//Debug.Log("reNameFile:" + ret);
		// 检查同名资源
		while (true)
		{
			bool isHaveSame = false;
			foreach (var item in mapMd5Files)
			{
				string filename0 = getFileName(item.Key);
				string filename1 = getFileName(ret);
				if (filename0 == filename1 && !item.Key.Contains(ret))
				{
					ret = ret.Replace(outFormat, "");
					ret += "_";
					ret += outFormat;
					isHaveSame = true;
				}
			}
			if (!isHaveSame)
				break;
		}
		mapMd5Files[ret] = ""; // 值不做实际操作
		return ret;
	}

	static void PopAssetDependencies()
	{
		for (int i = 0; i < nDependenciesCount; i++)
		{
			BuildPipeline.PopAssetDependencies();
		}
	}

	static void CompressFiles()
	{
		for (int i = 0; i < m_listNeedCompress.Count; i++)
		{
			string zipPaht = SavePath.Replace("/data", "/zip");
			string tmpPath = (m_listNeedCompress[i] + ".zip").Replace(SavePath, zipPaht);

			LZMPEditHelper.CompressFileLZMAThread(m_listNeedCompress[i], tmpPath);
		}
		LZMPEditHelper.CompressFileLZMAThread(SavePath + "/Files.assetBundle", (SavePath + "/Files.assetBundle.zip").Replace("/data/", "/zip/"));
	}

	static void Clear()
	{
		buildList.Clear();
		nDependenciesCount = 0;
		DicDependencies.Clear();
		m_listNeedCompress.Clear();
	}

	static void GetLocalDependFile(string path)
	{
		try
		{
			string zipPath = "";
			int nIndex = path.LastIndexOf("/data");
			if (nIndex != -1)
				zipPath = path.Substring(0, nIndex) + "/zip";
			LZMPEditHelper.DecompressFile(zipPath + "/Files" + outFormat + ".zip", path + "/Files" + outFormat);
			byte[] verTmp = File.ReadAllBytes(path + "/Files" + outFormat);
			DicDependencies = JsonMapper.ToObject<Dictionary<string, string>>(Encoding.UTF8.GetString(verTmp));
		}
		catch (System.Exception e)
		{
		}		
	}

	static void GetLocalMd5File(string path)
	{
		try
		{
			byte[] verTmp = File.ReadAllBytes(path + "/../md5_BundleRes.txt");
			mapMd5Files = JsonMapper.ToObject<Dictionary<string, string>>(Encoding.UTF8.GetString(verTmp));
		}
		catch (System.Exception e)
		{
		}	
	}

	static void UpdateDependFile(string path)
	{
		string dataJson = JsonMapper.ToJson(DicDependencies);
		File.WriteAllBytes(path + "/Files" + outFormat, new UTF8Encoding().GetBytes(dataJson));
	}

	static string getFileName(string path)
	{
		path = path.Replace('\\', '/');
		if (path.Contains("/")) 
			path = path.Substring(path.LastIndexOf('/'));
		return path;
	}

	static string rePath(string path)
	{
		string ret = path.Replace('\\', '/');
		ret = ret.Replace(' ', '_');
		return ret;
	} 
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity AssetBundle自动打包依赖包是指利用Unity引擎中的AssetBundle系统,将游戏中需要的资源文件进行打包,并自动包含其所依赖的其他资源文件。 首先,我们需要使用Unity编辑器中的AssetBundle功能,对需要打包的资源进行管理和设置。通过选择对应的资源文件,在其Inspector面板中设置AssetBundle属性,包括设置该资源所属的AssetBundle名称、变体名称以及是否包含所有依赖关系等。 在设置好所有资源的AssetBundle属性后,我们需要编写脚本来自动打包这些资源。Unity提供了相关的API来实现此功能。我们可以使用Unity的BuildPipeline类中的BuildAssetBundles方法来自动打包资源。该方法需要传入打包目标路径、打包选项等参数,然后会根据资源的AssetBundle属性自动将资源及其依赖打包到指定路径中。 打包完成后,我们可以将生成的AssetBundle部署到游戏的服务器或者客户端中,通过代码动态加载和使用这些资源。在运行时,我们可以使用AssetBundle.LoadFromFile或者AssetBundle.LoadFromMemory等方法来加载指定的AssetBundle文件,并根据需要加载其中的资源对象,然后进行相应的操作和使用。 通过AssetBundle系统的自动打包功能,我们可以实现游戏资源的灵活管理和优化,减小游戏安装包的大小,并根据具体需求动态加载和卸载资源,提高游戏的性能和效率。同时,通过合理设置资源的AssetBundle属性,我们还可以实现资源的增量更新等功能,提升游戏的可玩性和扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值