/// <summary> /// 记录压缩前文件大小和md5码,以及资源类型(是否包含于整包,是否是补丁资源) /// </summary> private void RecordFileRealSize() { string buildPath = BuilderPreference.BUILD_PATH; StringBuilder sb = new StringBuilder(); AssetBuildRule[] rules = AssetBuildRuleManager.Instance.Rules; Dictionary <string, AssetBuildRule> ruleMap = new Dictionary <string, AssetBuildRule>(); for (int i = 0; i < rules.Length; i++) { List <AssetBuildRule> ruleList = rules[i].TreeToList(); for (int j = 0; j < ruleList.Count; j++) { ruleMap[ruleList[j].AssetBundleName] = ruleList[j]; } } foreach (AssetBuildRule bundle in ruleMap.Values) { string format = string.Format("{0}|AssetType:{1}|DownloadOrder:{2}", BuildUtil.FormatBundleName(bundle), (int)bundle.PackageType, bundle.DownloadOrder); sb.AppendLine(format); } // save temp size file string savePath = buildPath + "/tempsizefile.txt"; if (File.Exists(savePath)) { File.Delete(savePath); } File.WriteAllText(savePath, sb.ToString()); Builder.AddBuildLog("<Asset Config Building>Record file real size"); }
/// <summary> /// 读取lua md5配置文件 /// </summary> private void ReadLuaMd5FromFile(Dictionary <string, Dictionary <string, string> > luaMd5Dict) { string luaMd5File = BuilderPreference.BUILD_PATH + "/luamd5.txt"; if (!File.Exists(luaMd5File)) { return; } string[] lines = File.ReadAllLines(luaMd5File); for (int i = 0; i < lines.Length; ++i) { if (!string.IsNullOrEmpty(lines[i])) { var temps = lines[i].ToLower().Split('|'); if (!luaMd5Dict.ContainsKey(temps[0])) { luaMd5Dict.Add(temps[0], new Dictionary <string, string>()); } luaMd5Dict[temps[0]].Add(temps[1], temps[2]); } // UpdateProgress(i, lines.Length, "Getting lua md5..."); } Builder.AddBuildLog("<Lua Building> Getting lua md5..."); // EditorUtility.ClearProgressBar(); // AssetDatabase.Refresh(); }
public override IEnumerator OnBuilding() { //打包测试包 CopyPackableFiles(); yield return(null); CompressWithZSTD(1024 * 1024 * 10); while (compressIndex < compressCount) { yield return(null); } AssetDatabase.Refresh(); genPacklistFile(); Builder.AddBuildLog("<SubPackage Building>Compress Zstd Finished..."); yield return(null); if (isBuildApp) { BuildApp(false, false); Builder.AddBuildLog("<SubPackage Building>Build App Finished..."); } }
/// <summary> /// 从上一版本替换不需要增量更新的lua bundle文件 /// </summary> private void CopyNoChangeLuaFiles(HashSet <string> copyLuaFiles) { if (copyLuaFiles.Count <= 0) { return; } int index = 0; foreach (var file in copyLuaFiles) { string fromPath = string.Concat(BuilderPreference.TEMP_ASSET_PATH, "/lua/", file); string toPath = string.Concat(BuilderPreference.BUILD_PATH, "/lua/", file); if (File.Exists(fromPath)) { File.Copy(fromPath, toPath, true); } // UpdateProgress(index++, luaMd5Dict.Count, "Copy no change files..."); } // EditorUtility.ClearProgressBar(); Builder.AddBuildLog("<Lua Building> Copy no change lua files to bundle path "); AssetDatabase.Refresh(); }
public override IEnumerator OnBuilding() { CopyAllBundles(); yield return(null); CompressWithZSTD(1024 * 1024 * 5); while (compressIndex < compressCount) { yield return(null); } AssetDatabase.Refresh(); genPacklistFile(); Builder.AddBuildLog("<FullPackage Building> Compress zstd finish !"); yield return(null); if (isBuildApp) { string appPath = BuildApp(true, isForceUpdate); Builder.AddBuildLog("<FullPackage Building>Build App Finished..."); EditorUtility.RevealInFinder(appPath); ResetConfig(); } }
public override IEnumerator OnBuilding() { yield return(null); //1.清除Assetbundle标记 BuildUtil.ClearAssetBundleName(); AssetDatabase.Refresh(); Builder.AddBuildLog("<Assetbundle Building> clear all assetbundle names "); yield return(null); //重新设置AB分配 this.SetAbName(); yield return(null); //开始启动Unity打包 bool result = this.buildAssetBundle(!Builder.IsDebug); if (!result) { //打包失败,停止继续处理 this.Builder.CanleBuild(); } AssetDatabase.Refresh(); yield return(null); PackPlayerModelTexture(); AssetDatabase.Refresh(); }
/// <summary> /// 建立ab映射文件 /// </summary> private void BuildBundleNameMapFile() { if (Builder.AssetMaps == null) { return; } string savePath = BuilderPreference.BUILD_PATH + "/bundlemap.ab"; StringBuilder sb = new StringBuilder(); foreach (AssetMap asset in Builder.AssetMaps.Values) { if (!asset.IsBinding) { continue; } int rootLength = 0; foreach (string rootFolder in BuilderPreference.BundleMapFile) { if (asset.AssetPath.StartsWith(rootFolder)) { rootLength = rootFolder.Length; break; } } if (rootLength <= 0) { continue; } string assetName = asset.AssetPath.Substring(rootLength + 1); if (asset.Rule.FileFilterType == FileType.Scene) { assetName = Path.GetFileName(asset.AssetPath); } string abName = BuildUtil.FormatBundleName(asset.Rule); int preload = asset.Rule.LoadType == ELoadType.PreLoad ? 1 : 0; string str = string.Format("{0}|{1}.{2}|{3}", assetName.Split('.')[0].ToLower(), abName, BuilderPreference.VARIANT_V1, preload); sb.AppendLine(str); } if (File.Exists(savePath)) { File.Delete(savePath); } BuildUtil.SwapPathDirectory(savePath); File.WriteAllBytes(savePath, Crypto.Encode(Riverlake.Encoding.GetBytes(sb.ToString()))); Builder.AddBuildLog("<Asset Config Building> Gen bundle name map file !"); }
void ResetConfig() { string resources_path = "Assets/Resources/"; if (File.Exists(resources_path + "config1.tmp")) { File.WriteAllText(resources_path + "config.txt", File.ReadAllText(resources_path + "config1.tmp")); File.Delete(resources_path + "config1.tmp"); AssetDatabase.Refresh(); } Builder.AddBuildLog("<FullPackage Building> reset config !"); }
public void CopyAssets(string fromPath) { string toPath = BuilderPreference.ASSET_PATH; if (Directory.Exists(toPath)) { Directory.Delete(toPath, true); } Directory.CreateDirectory(toPath); var dirInfo = new DirectoryInfo(fromPath); Builder.AddBuildLog("<Compress Building> Copying assets..."); int index = 0; FileInfo[] files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); List <string[]> comprssFiles = new List <string[]>(); foreach (var file in files) { index++; // ShowProgress("Copying assets...", (float)index / (float)files.Length); if (file.Name.EndsWith(".meta") || file.Name.EndsWith(".manifest") || file.Name.Contains("config.txt")) { continue; } string relativePath = BuildUtil.RelativePaths(file.FullName); string to = relativePath.Replace(fromPath, toPath); BuildUtil.SwapPathDirectory(to); if (relativePath.EndsWith(".ab")) { comprssFiles.Add(new [] { relativePath, to }); } else { File.Copy(relativePath, to, true); } } totalCompressCount = comprssFiles.Count; compressIndex = 0; for (int i = 0; i < comprssFiles.Count; i++) { ThreadPool.QueueUserWorkItem(onThreadCompress, comprssFiles[i]); } }
/// <summary> /// 启动Unity打包Assetbundle /// </summary> /// <param name="copyAssets"></param> /// <returns></returns> private bool buildAssetBundle(bool copyAssets = true) { try { if (copyAssets) { CopyToAssetBundle(); } RemoveNotExsitBundles(); // 更新资源版本号 string bundlePath = BuilderPreference.BUILD_PATH; Builder.GameVersion.VersionIncrease(); PlayerSettings.bundleVersion = Builder.GameVersion.ToString(); File.WriteAllText(bundlePath + "/version.txt", Builder.GameVersion.ToString()); Builder.SaveVersion(); AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(bundlePath, BuilderPreference.BuildBundleOptions, EditorUserBuildSettings.activeBuildTarget); if (manifest == null) { throw new Exception("Build assetbundle error"); } string manifestPath = string.Concat(bundlePath, "/", BuilderPreference.PlatformTargetFolder.ToLower()); if (File.Exists(manifestPath)) { byte[] bytes = File.ReadAllBytes(manifestPath); File.Delete(manifestPath); File.WriteAllBytes(manifestPath + ".ab", bytes); } else { Debug.LogError("<<BuildAssetBundle>> Cant find root manifest. ps:" + manifestPath); } Builder.AddBuildLog("<Assetbundle Building> build assetbundles finish !"); return(true); } catch (Exception e) { Debug.LogException(e); return(false); } }
/// <summary> /// 记录lua的md5码 /// </summary> private void RecordLuaMd5() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < luaPaths.Length; i++) { if (!Directory.Exists(luaPaths[i])) { continue; } string luaDataPath = luaPaths[i].ToLower(); List <string> files = BuildUtil.SearchFiles(luaDataPath, SearchOption.AllDirectories); foreach (string f in files) { var path = f.ToLower(); if (!path.EndsWith(".lua")) { continue; } string newfile = f.Replace("assets/", ""); string dir = Path.GetDirectoryName(f); string relativeDir = dir.Replace(luaDataPath, ""); string bundleName = formatLuaBundleName(relativeDir); string md5 = MD5.ComputeHashString(path); sb.AppendLine(string.Format("{0}|{1}|{2}", bundleName, newfile, md5)); //bundleName } // UpdateProgress(i, luaPaths.Length, "Recording lua md5..."); } // EditorUtility.ClearProgressBar(); // AssetDatabase.Refresh(); //重写记录文件 string luaMd5File = BuilderPreference.BUILD_PATH + "/luamd5.txt"; File.WriteAllText(luaMd5File, sb.ToString()); Builder.AddBuildLog("<Lua Building> record lua md5 finish "); }
/// <summary> /// 删除被清除的Bundle /// </summary> private void RemoveNotExsitBundles() { string[] files = Directory.GetFiles(BuilderPreference.BUILD_PATH, "*.ab", SearchOption.AllDirectories); Builder.AddBuildLog("<Assetbundle Building> Removing not exsit bundles..."); string[] assetBundles = AssetDatabase.GetAllAssetBundleNames(); HashSet <string> allBundleSet = new HashSet <string>(assetBundles); for (int i = 0; i < files.Length; ++i) { var file = files[i].Replace("\\", "/"); string fileName = Path.GetFileName(file); if (!allBundleSet.Contains(fileName)) { File.Delete(file); File.Delete(file + ".meta"); File.Delete(file + ".manifest"); File.Delete(file + ".manifest.meta"); } } AssetDatabase.Refresh(); }
private void CopyAllBundles() { string targetPath = BuilderPreference.StreamingAssetsPlatormPath; if (Directory.Exists(targetPath)) { Directory.Delete(targetPath, true); } Directory.CreateDirectory(targetPath); string buildPath = BuilderPreference.BUILD_PATH; HashSet <string> withExtensions = new HashSet <string>() { ".ab", ".unity3d", ".txt", ".conf", ".pb", ".bytes" }; List <string> files = BuildUtil.SearchIncludeFiles(buildPath, SearchOption.AllDirectories, withExtensions); Builder.AddBuildLog("<FullPackage Building> Copy all bundle ..."); // int buildPathLength = buildPath.Length + 1; for (int i = 0; i < files.Count; ++i) { string fileName = Path.GetFileName(files[i]); if (fileName == "tempsizefile.txt" || fileName == "luamd5.txt") { continue; } //ABPackHelper.ShowProgress("Copying files...", (float)i / (float)files.Length); string streamBundlePath = files[i].Replace(buildPath, targetPath); BuildUtil.SwapPathDirectory(streamBundlePath); File.Copy(files[i], streamBundlePath); } AssetDatabase.Refresh(); // ABPackHelper.ShowProgress("", 1); }
public void CopyToAssetBundle() { Builder.AddBuildLog("<Assetbundle Building> Copying to AssetBundle folder..."); string fromPath = BuilderPreference.TEMP_ASSET_PATH; string toPath = BuilderPreference.BUILD_PATH; if (Directory.Exists(toPath)) { Directory.Delete(toPath, true); } Directory.CreateDirectory(toPath); var dirInfo = new DirectoryInfo(fromPath); if (dirInfo.Exists) { int index = 0; FileInfo[] files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); foreach (var file in files) { index++; if (file.Name.Contains("config.txt")) { continue; } string relativePath = file.FullName.Replace("\\", "/"); string to = relativePath.Replace(fromPath, toPath); BuildUtil.SwapPathDirectory(to); File.Copy(relativePath, to, true); } } Builder.AddBuildLog("<Assetbundle Building> Copying to AssetBundle folder end ..."); }
/// <summary> /// 拷贝协议文件 /// </summary> private void CopyHandleBundle() { string bundleLuaPath = string.Concat(BuilderPreference.BUILD_PATH, "/lua/"); for (int i = 0; i < luaPaths.Length; i++) { if (!Directory.Exists(luaPaths[i])) { continue; } string luaDataPath = luaPaths[i].ToLower(); List <string> includeFiles = BuildUtil.SearchFiles(luaDataPath, SearchOption.AllDirectories); //拷贝protocol foreach (string f in includeFiles) { if (f.EndsWith(".lua")) { continue; } var cmpStr = f.ToLower(); if (cmpStr.Contains("protocol/")) { string newPath = f.Replace(luaDataPath, bundleLuaPath); BuildUtil.SwapPathDirectory(newPath); File.Copy(f, newPath, true); } } } Builder.AddBuildLog("<Lua Building> copy lua handle bundles "); }
public void CopyToTempAssets() { string fromPath = BuilderPreference.BUILD_PATH; string toPath = BuilderPreference.TEMP_ASSET_PATH; if (Directory.Exists(toPath)) { Directory.Delete(toPath, true); } Directory.CreateDirectory(toPath); var dirInfo = new DirectoryInfo(fromPath); Builder.AddBuildLog("<Compress Building> Copying to temp assets..."); int index = 0; FileInfo[] files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories); foreach (var file in files) { index++; // ShowProgress("Copying to temp assets...", (float)index / (float)files.Length); if (file.Name.EndsWith(".meta") || file.Name.Contains("config.txt")) { continue; } string relativePath = BuildUtil.RelativePaths(file.FullName); string to = relativePath.Replace(fromPath, toPath); BuildUtil.SwapPathDirectory(to); File.Copy(relativePath, to, true); } // ShowProgress("", 1); }
private void BuildFileIndex() { Builder.AddBuildLog("<Asset Config Building> start Build File Index ...."); string resPath = BuilderPreference.BUILD_PATH + "/"; //----------------------创建文件列表----------------------- string newFilePath = resPath + "files.txt"; if (File.Exists(newFilePath)) { File.Delete(newFilePath); } string tempSizeFile = resPath + "tempsizefile.txt"; Dictionary <string, string> assetTypeDict = new Dictionary <string, string>(); if (File.Exists(tempSizeFile)) { var sizeFileContent = File.ReadAllText(tempSizeFile); var temps = sizeFileContent.Split('\n'); for (int i = 0; i < temps.Length; ++i) { if (!string.IsNullOrEmpty(temps[i])) { var temp = temps[i].Split('|'); if (temp.Length != 2 && temp.Length != 3) { throw new System.IndexOutOfRangeException(); } var assetType = temp[1]; if (temp.Length == 3) { assetType += "|" + temp[2]; } assetTypeDict.Add(temp[0], assetType); //UpdateProgress(i, temps.Length, temps[i]); } } // EditorUtility.ClearProgressBar(); } List <string> includeFiles = BuildUtil.SearchFiles(resPath, SearchOption.AllDirectories); HashSet <string> excludeSuffxs = new HashSet <string>() { ".DS_Store", ".manifest" }; //排除文件 BuildUtil.SwapPathDirectory(newFilePath); using (FileStream fs = new FileStream(newFilePath, FileMode.CreateNew)) { StreamWriter sw = new StreamWriter(fs); for (int i = 0; i < includeFiles.Count; i++) { string file = includeFiles[i]; string ext = Path.GetExtension(file); if (excludeSuffxs.Contains(ext) || file.EndsWith("apk_version.txt") || file.Contains("tempsizefile.txt") || file.Contains("luamd5.txt")) { continue; } string md5 = MD5.ComputeHashString(file); int size = (int)new FileInfo(file).Length; string value = file.Replace(resPath, string.Empty).ToLower(); if (assetTypeDict.ContainsKey(value)) { sw.WriteLine("{0}|{1}|{2}|{3}", value, md5, size, assetTypeDict[value]); } else { sw.WriteLine("{0}|{1}|{2}", value, md5, size); } // UpdateProgress(i, includeFiles.Count, file); } sw.Close(); } // EditorUtility.ClearProgressBar(); Builder.AddBuildLog("<Asset Config Building> Build File Index end ...."); }
protected string BuildApp(bool packAllRes, bool forceUpdate) { Builder.AddBuildLog("Build App Start !... packAllRes:" + packAllRes + ",force update:" + forceUpdate); var option = BuildOptions.None; if (Builder.IsDebug) { option |= BuildOptions.AllowDebugging; } if (Builder.IsBuildDev) { option |= BuildOptions.Development; } if (Builder.IsAutoConnectProfile) { option |= BuildOptions.ConnectWithProfiler; } string dir = Path.GetDirectoryName(Builder.ApkSavePath); string fileName = Path.GetFileNameWithoutExtension(Builder.ApkSavePath); string time = DateTime.Now.ToString("yyyyMMdd"); string flag = string.Empty; BuildTarget buildTarget = EditorUserBuildSettings.activeBuildTarget; string final_path = string.Empty; if (buildTarget != BuildTarget.iOS) { SDKConfig curSdkConfig = Builder.CurrentConfigSDK; for (int i = 0; i < curSdkConfig.items.Count; i++) { var item = Builder.CurrentConfigSDK.items[i]; BuildOptions targetOptions = option; if (item.development == 1) { targetOptions |= BuildOptions.Development; flag = packAllRes ? "_allpack_dev_v" : "_subpack_dev_v"; } else if (item.use_sdk == 1) { flag = packAllRes ? "_allpack_sdk_v" : "_subpack_sdk_v"; } else { flag = packAllRes ? "_allpack_test_v" : "_subpack_test_v"; } if (buildTarget == BuildTarget.Android) { final_path = string.Concat(dir, "/", fileName, "_", time, flag, Builder.GameVersion.ToString(), ".apk"); if (File.Exists(final_path)) { File.Delete(final_path); } // 写入并保存sdk启用配置 // item.CopyConfig(); // item.CopySDK(); // item.SetPlayerSetting(curSdkConfig.splash_image); // item.SaveSDKConfig(); //item.SplitAssets(sdkConfig.split_assets); if (item.update_along == 0 && forceUpdate) { if (Directory.Exists(Application.streamingAssetsPath)) { Directory.Delete(Application.streamingAssetsPath, true); } } } else if (buildTarget == BuildTarget.StandaloneWindows64 || buildTarget == BuildTarget.StandaloneWindows) { final_path = string.Concat(dir, "/", fileName, "_", time, flag, Builder.GameVersion.ToString(), ".exe"); if (Directory.Exists(final_path)) { Directory.Delete(final_path, true); } item.CopyConfig(); } AssetDatabase.Refresh(); BuildUtil.SwapPathDirectory(final_path); BuildPipeline.BuildPlayer(GetBuildScenes(), final_path, buildTarget, targetOptions); item.ClearSDK(); } } else if (buildTarget == BuildTarget.iOS) { // 在上传目录新建一个ios_check.txt文件用于判断当前包是否出于提审状态 string checkFile = BuilderPreference.ASSET_PATH + "/ios_check.txt"; if (File.Exists(checkFile)) { File.Delete(checkFile); } File.WriteAllText(checkFile, "1"); XCConfigItem configItem = XCConfigItem.ParseXCConfig(XCodePostProcess.config_path); if (configItem != null) { PlayerSettings.applicationIdentifier = configItem.bundleIdentifier; PlayerSettings.productName = configItem.product_name; configItem.CopyConfig(); } // IOSGenerateHelper.IOSConfusing(); AssetDatabase.Refresh(); BuildPipeline.BuildPlayer(GetBuildScenes(), Builder.ApkSavePath, buildTarget, option); } Resources.UnloadUnusedAssets(); GC.Collect(); Builder.AddBuildLog("[end]Build App Finish !..."); return(final_path); }
/// <summary> /// 比较文件夹下lua更新情况,用来做lua的增量更新 /// </summary> private void CompareLuaMd5(Dictionary <string, Dictionary <string, string> > luaMd5Dict) { int index = 0; HashSet <string> copyLuaFiles = new HashSet <string>(); foreach (string luaBundleName in luaMd5Dict.Keys) { var relativePath = luaBundleName.Replace('-', '/'); string dir; if (relativePath.EndsWith("/lua")) { dir = "Assets/" + relativePath.Substring(0, relativePath.LastIndexOf("/")); } else { dir = "Assets/" + relativePath; } if (!Directory.Exists(dir)) { continue; } string[] files = Directory.GetFiles(dir, "*.lua", SearchOption.TopDirectoryOnly); bool needCopy = true; // 如果文件夹下数量有变 说明有更改 Dictionary <string, string> luaMaps = luaMd5Dict[luaBundleName]; if (luaMaps.Count == files.Length) { for (int i = 0; i < files.Length; ++i) { var cmpStr = files[i].ToLower().Replace("\\", "/"); string newfile = cmpStr.Replace(AppDataPath + "/", ""); var curMd5 = MD5.ComputeHashString(files[i]); // 如果文件夹下有新增lua文件 说明有更改 if (!luaMaps.ContainsKey(newfile)) { needCopy = false; } // 如果lua文件md5值有变动 说明有更改 else if (luaMaps[newfile] != curMd5) { needCopy = false; } if (!needCopy) { break; } } } else { needCopy = false; } // 文件夹下没有更改的资源,将新的lua包替换回上一个版本 if (needCopy) { for (int i = 0; i < luaPaths.Length; ++i) { if (!Directory.Exists(luaPaths[i])) { continue; } var temp = luaPaths[i].ToLower(); if (dir.Contains(temp)) { var relativeDir = dir.Replace(temp, "").TrimEnd('/'); var bundleName = formatLuaBundleName(relativeDir); if (!copyLuaFiles.Contains(bundleName)) { copyLuaFiles.Add(bundleName); } break; } } } // UpdateProgress(index++, luaMd5Dict.Count, "Comparing lua md5..."); } // end foreach Builder.AddBuildLog("<Lua Building> CompareLuaMd5 finish "); CopyNoChangeLuaFiles(copyLuaFiles); }
/// <summary> /// 复制分包资源到StreamingAssets目录下 /// </summary> void CopyPackableFiles() { string targetPath = BuilderPreference.StreamingAssetsPlatormPath; if (Directory.Exists(targetPath)) { Directory.Delete(targetPath, true); } Directory.CreateDirectory(targetPath); string bundlePath = BuilderPreference.BUILD_PATH; //拷贝StreamAsset目录中的资源 AssetBuildRule[] rules = AssetBuildRuleManager.Instance.Rules; Dictionary <string, AssetBuildRule> ruleMap = new Dictionary <string, AssetBuildRule>(); for (int i = 0; i < rules.Length; i++) { List <AssetBuildRule> ruleList = rules[i].TreeToList(); for (int j = 0; j < ruleList.Count; j++) { ruleMap[ruleList[j].AssetBundleName] = ruleList[j]; } } //只拷贝整包类型的文件 foreach (AssetBuildRule bundleRule in ruleMap.Values) { if (bundleRule.PackageType != PackageAssetType.InPackage) { continue; } string assetBundleName = BuildUtil.FormatBundleName(bundleRule); string buildBundlePath = string.Concat(bundlePath, "/", assetBundleName, BuilderPreference.VARIANT_V1); if (!File.Exists(buildBundlePath)) { continue; } string streamBundlePath = string.Concat(targetPath, "/", assetBundleName, BuilderPreference.VARIANT_V1); BuildUtil.SwapPathDirectory(streamBundlePath); File.Copy(buildBundlePath, streamBundlePath); } Action <List <string>, string> copyFiles = (filePaths, rootPath) => { for (int i = 0; i < filePaths.Count; i++) { string relativePath = filePaths[i]; if (!File.Exists(relativePath)) { continue; } string streamBundlePath = relativePath.Replace(rootPath, targetPath); BuildUtil.SwapPathDirectory(streamBundlePath); File.Copy(relativePath, streamBundlePath); } }; HashSet <string> includeExtensions = new HashSet <string>() { ".ab", ".unity3d", ".txt", ".conf", ".pb", ".bytes" }; //拷贝bundle配置目录的配置文件 string[] copyTargetPaths = new[] { string.Concat(bundlePath, "/files.txt"), string.Concat(bundlePath, "/bundlemap.ab"), string.Concat(bundlePath, "/font.ab"), string.Concat(bundlePath, "/shader.ab"), }; List <string> files = new List <string>(copyTargetPaths); copyFiles(files, bundlePath); //拷贝Lua目录代码 string luaBundlePath = string.Concat(bundlePath, "/lua"); files = BuildUtil.SearchIncludeFiles(luaBundlePath, SearchOption.AllDirectories, includeExtensions); copyFiles(files, luaBundlePath); Builder.AddBuildLog("<Sub Package Building>Copy sub package files ..."); AssetDatabase.Refresh(); }
private void BuildLuaBundles() { ClearAllLuaFiles(); string output = BuilderPreference.BUILD_PATH + "/lua"; BuildUtil.SwapDirectory(output); BuildAssetBundleOptions options = BuildAssetBundleOptions.DisableWriteTypeTree | BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.UncompressedAssetBundle; string streamDir = "Assets/lua/"; //临时打包目录 foreach (string luaPath in luaPaths) { CopyLuaBytesFiles(luaPath, streamDir); } AssetDatabase.Refresh(); string[] dirs = Directory.GetDirectories(streamDir, "*", SearchOption.AllDirectories); List <AssetBundleBuild> abbs = new List <AssetBundleBuild>(); for (int i = 0; i < dirs.Length; i++) { string relativePath = dirs[i].Replace("\\", "/"); AssetBundleBuild abb = GenLuaBundleBuild(relativePath); abbs.Add(abb); } AssetBundleBuild rootBundle = GenLuaBundleBuild(streamDir); abbs.Add(rootBundle); AssetBundleBuild[] buildArr = abbs.Where(b => !string.IsNullOrEmpty(b.assetBundleName)).ToArray(); if (BuildPipeline.BuildAssetBundles(output, buildArr, options, EditorUserBuildSettings.activeBuildTarget)) { string[] bundles = Directory.GetFiles(output, "*.unity3d", SearchOption.AllDirectories); Builder.AddBuildLog("<Lua Building> Crypto lua files ! count is " + bundles.Length); for (int i = 0; i < bundles.Length; i++) { string bundlePath = bundles[i]; byte[] bytes = File.ReadAllBytes(bundlePath); //for (int i = 0; i < bytes.Length; ++i) //{ // bytes[i] = (byte)(bytes[i] ^ 0xffff); //} //var buffer = Crypto.Encode(bytes); File.WriteAllBytes(bundlePath, Crypto.SimpleCrypto(bytes)); } } Directory.Delete(streamDir, true); AssetDatabase.Refresh(); Builder.AddBuildLog("<Lua Building> Build Lua Bundles success "); }
/// <summary> /// 设置资源的AB名称 /// </summary> private void SetAbName() { string savePath = BuilderPreference.BUILD_PATH + "/tempsizefile.txt"; if (File.Exists(savePath)) { File.Delete(savePath); } AssetDatabase.Refresh(); // 设置ab名 AssetBuildRule[] rules = AssetBuildRuleManager.Instance.Rules; Builder.AddBuildLog("<Assetbundle Building> Start set AssetBundleName..."); Dictionary <string, List <AssetBuildRule> > path2ruleMap = new Dictionary <string, List <AssetBuildRule> >(); for (int i = 0; i < rules.Length; i++) { List <AssetBuildRule> ruleList = rules[i].TreeToList(); for (int j = 0; j < ruleList.Count; j++) { AssetBuildRule rule = ruleList[j]; List <AssetBuildRule> pathRules = null; if (!path2ruleMap.TryGetValue(rule.Path, out pathRules)) { pathRules = new List <AssetBuildRule>(); path2ruleMap[rule.Path] = pathRules; } pathRules.Add(rule); } } //获取根目录下的所有文件 List <string> files = new List <string>(); for (int i = 0; i < rules.Length; i++) { List <string> rootFiles = BuildUtil.SearchFiles(rules[i], path2ruleMap); if (rootFiles != null) { files.AddRange(rootFiles); } } Builder.AssetMaps = new Dictionary <string, AssetMap>(); Dictionary <string, AssetMap> assetMaps = Builder.AssetMaps; //构建映射关系 for (int i = 0; i < files.Count; i++) { AssetMap fileAssetMap = null; FileType fileType = BuildUtil.GetFileType(new FileInfo(files[i])); if (!assetMaps.TryGetValue(files[i], out fileAssetMap)) { AssetBuildRule rule = findRuleByPath(files[i], path2ruleMap, fileType); if (rule == null) { Debug.LogError("Cant find bundle rule!" + files[i]); } fileAssetMap = new AssetMap(files[i], rule); assetMaps[files[i]] = fileAssetMap; } fileAssetMap.IsBinding = true; //显示设置bundle规则的文件 //被忽略的规则不查找依赖 if (fileAssetMap.Rule.BuildType == (int)BundleBuildType.Ignore) { continue; } string[] dependency = AssetDatabase.GetDependencies(files[i]); for (int j = 0; j < dependency.Length; j++) { string relativePath = BuildUtil.Replace(dependency[j]); string extension = Path.GetExtension(dependency[j]); if (BuilderPreference.ExcludeFiles.Contains(extension) || relativePath.Equals(files[i])) { continue; } AssetMap assetMap = null; FileType depFileType = BuildUtil.GetFileType(new FileInfo(relativePath)); if (!assetMaps.TryGetValue(relativePath, out assetMap)) { AssetBuildRule rule = findRuleByPath(relativePath, path2ruleMap, depFileType); rule = rule == null ? fileAssetMap.Rule : rule; assetMap = new AssetMap(relativePath, rule); assetMaps[relativePath] = assetMap; } assetMap.AddReference(fileAssetMap); fileAssetMap.AddDependency(assetMap); } } //根据明确的子目录设置AB名,即定义了指定的打包规则的目录 foreach (AssetMap asset in assetMaps.Values) { if (asset.Rule.BuildType == (int)BundleBuildType.Ignore || !asset.IsBinding) { continue; } // Builder.AddBuildLog(string.Format("set assetbundle name , path {0} : {1}", asset.AssetPath, asset.Rule.AssetBundleName)); BuildUtil.SetAssetbundleName(asset.AssetPath, asset.Rule); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Builder.AddBuildLog("<Assetbundle Building> set assetbundle name ... end"); //设置依赖文件的Assetbundle分配 this.checkDependency(assetMaps); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Builder.AddBuildLog("<Assetbundle Building> Check Dependency... end"); }
/// <summary> /// 特殊处理主角相关的贴图 /// </summary> /// <summary> /// 特殊处理主角相关的贴图 /// </summary> private void PackPlayerModelTexture() { // 删除与主角合并Texture相关的AB string bundlePath = BuilderPreference.BUILD_PATH; string[] tempFiles = Directory.GetDirectories(bundlePath, "*", SearchOption.AllDirectories) .Where(f => f.Contains("_tmp")).ToArray(); Builder.AddBuildLog("<Assetbundle Building> delete tmp assets ..." + tempFiles.Length); for (int i = 0; i < tempFiles.Length; i++) { string dirPath = BuildUtil.Replace(tempFiles[i]); Directory.Delete(dirPath, true); string relativePath = BuildUtil.RelativePaths(tempFiles[i]); File.Delete(relativePath + ".meta"); } //合并贴图 string root = "Assets/Models/RoleModels/"; string[] subFolder = new string[3] { "Players", "Weapons", "Wings" }; Dictionary <string, List <string> > textureDict = new Dictionary <string, List <string> >(); Builder.AddBuildLog("<Assetbundle Building> Get model texture map..."); for (int i = 0; i < subFolder.Length; ++i) { string path = root + subFolder[i]; List <string> files = new List <string>(); string[] jpgs = Directory.GetFiles(path, "*.jpg", SearchOption.AllDirectories); files.AddRange(jpgs); string[] pngs = Directory.GetFiles(path, "*.png", SearchOption.AllDirectories); files.AddRange(pngs); for (int j = 0; j < files.Count; ++j) { var file = files[j].Replace("\\", "/").ToLower(); string id = Path.GetFileNameWithoutExtension(file).Replace("_light", ""); List <string> lists; if (!textureDict.TryGetValue(id, out lists)) { lists = new List <string>(); lists.Add(file); textureDict.Add(id, lists); } else { if (file.EndsWith(".png")) { lists.Insert(0, file); } else { lists.Add(file); } } } } string save_path = Path.Combine(BuilderPreference.BUILD_PATH, "/combinedtextures"); BuildUtil.SwapDirectory(save_path); int index = 0; Builder.AddBuildLog("<Assetbundle Building> Pack Model Texture..."); foreach (string fileName in textureDict.Keys) { List <string> files = textureDict[fileName]; if (fileName.Contains("_normal", StringComparison.OrdinalIgnoreCase)) { for (int i = 0; i < files.Count; ++i) { if (files[i].Contains("/Players/")) { if (File.Exists(files[i])) { File.Delete(fileName); break; } } } } if (files.Count < 2) { continue; } var file_path = string.Concat(save_path, "/", fileName, ".bytes").ToLower(); var pngBytes = File.ReadAllBytes(files[0]); var jpgBytes = File.ReadAllBytes(files[1]); using (var fs = new FileStream(file_path, FileMode.OpenOrCreate)) { byte[] intPngBuff = BitConverter.GetBytes(pngBytes.Length); fs.Write(intPngBuff, 0, 4); fs.Write(pngBytes, 0, pngBytes.Length); byte[] intJpgBuff = BitConverter.GetBytes(jpgBytes.Length); fs.Write(intJpgBuff, 0, 4); fs.Write(jpgBytes, 0, jpgBytes.Length); fs.Flush(); } index++; } //end foreach }
/// <summary> /// 压缩StreamAsset目录的资源 /// </summary> /// <param name="maxFileSize"></param> protected void CompressWithZSTD(long maxFileSize) { string outPutPath = BuilderPreference.StreamingAssetsPlatormPath; var dirInfo = new DirectoryInfo(outPutPath); var dirs = dirInfo.GetDirectories(); Dictionary <int, List <string> > allFiles = new Dictionary <int, List <string> >(); // data原始包控制在10M左右 long curSize = 0; int tmpIndex = 0; for (int i = 0; i < dirs.Length; ++i) { if (dirs[i].Name == "lua") { continue; } var abFileInfos = BuildUtil.SearchFiles(dirs[i].FullName, SearchOption.AllDirectories); for (int j = 0; j < abFileInfos.Count; ++j) { var relativePath = abFileInfos[j]; var data = new FileInfo(relativePath); if (data.Length >= maxFileSize) { curSize = 0; tmpIndex++; } else if (curSize >= maxFileSize) { curSize = 0; tmpIndex++; } if (curSize == 0) { allFiles.Add(tmpIndex, new List <string>()); } allFiles[tmpIndex].Add(relativePath); curSize += data.Length; } } // 合并生成的bundle文件,合成10M左右的小包(二进制) Builder.AddBuildLog("<Copresss zstd> merge and compress with zstd..."); compressIndex = 0; compressCount = allFiles.Count; foreach (var key in allFiles.Keys) { var tmpName = "data" + key; #if UNITY_IOS tmpName = IOSGenerateHelper.RenameResFileWithRandomCode(tmpName); #endif var savePath = string.Format("{0}/{1}.tmp", outPutPath, tmpName); List <string> mergePaths = allFiles[key]; ThreadPool.QueueUserWorkItem(onThreadCompress, new object[] { savePath, outPutPath, mergePaths }); } }