void RemoveNotExsitBundles() { string[] files = Directory.GetFiles(ABPackHelper.BUILD_PATH, "*.ab", SearchOption.AllDirectories); ABPackHelper.ShowProgress("", 0); List <string> tempBundles = new List <string>(); tempBundles.AddRange(abTypeMaps.Keys); for (int i = 0; i < files.Length; ++i) { var file = files[i].Replace("\\", "/"); ABPackHelper.ShowProgress("Removing bundles...", (float)i / (float)files.Length); bool exist = false; for (int j = 0; j < tempBundles.Count; j++) { if (file.Contains(tempBundles[j])) { exist = true; break; } } if (!exist) { File.Delete(files[i]); File.Delete(files[i] + ".meta"); File.Delete(files[i] + ".manifest"); File.Delete(files[i] + ".manifest.meta"); } } ABPackHelper.ShowProgress("", 1); AssetDatabase.Refresh(); }
void BuildAssetBundle() { ABPackHelper.CopyToAssetBundle(); RemoveNotExsitBundles(); // 更新资源版本号 string bundlePath = ABPackHelper.BUILD_PATH + LuaConst.osDir; gameVersion.VersionIncrease(); //PlayerSettings.bundleVersion = gameVersion.ToString(); File.WriteAllText(bundlePath + "/version.txt", gameVersion.ToString()); ABPackHelper.SaveVersion(gameVersion.ToString()); AssetDatabase.Refresh(); BuildPipeline.BuildAssetBundles(bundlePath, ABPackHelper.buildOptions, ABPackHelper.GetBuildTarget()); var manifestFile = ABPackHelper.BUILD_PATH + LuaConst.osDir + "/" + LuaConst.osDir; var saveABFile = ABPackHelper.BUILD_PATH + LuaConst.osDir + "/" + LuaConst.osDir.ToLower(); if (File.Exists(manifestFile)) { var bytes = File.ReadAllBytes(manifestFile); File.Delete(manifestFile); File.WriteAllBytes(saveABFile + ".ab", bytes); } else { Debug.LogError("<<BuildAssetBundle>> Cant find root manifest. ps:" + manifestFile); } AssetDatabase.Refresh(); }
void CopyCompressedData2IOSStreaming() { string to = Application.streamingAssetsPath; if (Directory.Exists(to)) { Directory.Delete(to, true); } Directory.CreateDirectory(to); string from = ABPackHelper.TEMP_ASSET_PATH + "IOSCompress"; string[] files = Directory.GetFiles(from, "*", SearchOption.AllDirectories); for (int i = 0; i < files.Length; ++i) { var dest = files[i].Replace("\\", "/").Replace(ABPackHelper.TEMP_ASSET_PATH.Replace("\\", "/") + "IOSCompress/", ""); var dirs = dest.Split('/'); string path = to; ABPackHelper.ShowProgress("copy for ios..." + dest, (float)i / (float)files.Length); foreach (var dir in dirs) { if (dir.Contains('.')) { continue; } path += "/" + dir; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } File.Copy(files[i], to + "/" + dest, true); } ABPackHelper.ShowProgress("copy compressed data for ios...", 1); AssetDatabase.Refresh(); }
void CopyAllBundles() { if (Directory.Exists(Application.streamingAssetsPath)) { Directory.Delete(Application.streamingAssetsPath, true); } string targetPath = Application.streamingAssetsPath + "/" + LuaConst.osDir; Directory.CreateDirectory(targetPath); string bundlePath = ABPackHelper.BUILD_PATH + LuaConst.osDir; List <string> withExtensions = new List <string>() { ".ab", ".unity3d", ".txt", ".conf", ".pb" }; string[] files = Directory.GetFiles(bundlePath, "*.*", SearchOption.AllDirectories) .Where(s => withExtensions.Contains(Path.GetExtension(s).ToLower())).ToArray(); ABPackHelper.ShowProgress("", 0); for (int i = 0; i < files.Length; ++i) { if (Path.GetFileName(files[i]) == "tempsizefile.txt" || Path.GetFileName(files[i]) == "luamd5.txt") { continue; } ABPackHelper.ShowProgress("Copying files...", (float)i / (float)files.Length); var tempStr = files[i].Replace(bundlePath, "").Replace("\\", "/").TrimStart('/'); var dirs = tempStr.Split('/'); var tempDir = targetPath; for (int j = 0; j < dirs.Length - 1; ++j) { tempDir += "/" + dirs[j]; if (!Directory.Exists(tempDir)) { Directory.CreateDirectory(tempDir); } } var file = ABPackHelper.GetRelativeAssetsPath(files[i]); bool needCopy = true; foreach (var key in abTypeMaps.Keys) { var value = abTypeMaps[key.ToLower()].Split('.'); if (file.Contains(key) && Convert.ToInt32(value[0]) == 3) { needCopy = false; break; } } if (needCopy) { File.Copy(files[i], targetPath + "/" + tempStr); } } AssetDatabase.Refresh(); ABPackHelper.ShowProgress("", 1); CompressWithZSTD(1024 * 1024 * 10); }
void BuildLuaAndCopyResources() { ABPackHelper.ShowProgress("", 1); AssetDatabase.Refresh(); Packager.BuildAssetResource(ABPackHelper.GetBuildTarget()); ABPackHelper.CopyAssets(ABPackHelper.BUILD_PATH + LuaConst.osDir); ABPackHelper.CopyToTempAssets(); AssetDatabase.Refresh(); }
public void SetPlayerSetting(string splash_image) { if (ABPackHelper.GetBuildTarget() == BuildTarget.Android || ABPackHelper.GetBuildTarget() == BuildTarget.iOS) { PlayerSettings.applicationIdentifier = "com." + company_name + "." + keystore_name.Replace('_', '.'); PlayerSettings.companyName = company_name; PlayerSettings.productName = protuct_name; Texture2D splashImg = AssetDatabase.LoadAssetAtPath <Texture2D>("Assets/SplashImg/" + splash_image + ".jpg"); PlayerSettings.virtualRealitySplashScreen = splashImg; var tex = AssetDatabase.LoadAssetAtPath <Texture2D>("Assets/AppIcon/" + app_icon + ".png"); BuildTargetGroup targetGroup = BuildTargetGroup.Android; if (ABPackHelper.GetBuildTarget() == BuildTarget.iOS) { targetGroup = BuildTargetGroup.iOS; } PlayerSettings.SetIconsForTargetGroup(targetGroup, new Texture2D[1] { tex }); if (ABPackHelper.GetBuildTarget() == BuildTarget.Android) { string keyStorePath = Application.dataPath.Replace("/Assets", "") + "/Public/KeyStore/password.txt"; var passwords = File.ReadAllLines(keyStorePath); string password = string.Empty; string aliasName = string.Empty; foreach (var pass in passwords) { var strs = pass.Split(':'); if (strs[0] == keystore_name) { password = strs[1].TrimEnd('\n'); aliasName = strs[2].TrimEnd('\n'); break; } } if (!string.IsNullOrEmpty(password)) { string storeName = Application.dataPath.Replace("/Assets", "") + "/Public/KeyStore/" + keystore_name + ".keystore"; PlayerSettings.Android.keystoreName = storeName.Replace("\\", "/"); PlayerSettings.Android.keystorePass = password; PlayerSettings.Android.keyaliasName = aliasName; PlayerSettings.Android.keyaliasPass = password; } else { PlayerSettings.Android.keyaliasName = "Unsigned"; } } AssetDatabase.Refresh(); } }
private static void RenameLuaFiles() { string rootPath = IOS_RES_PATH + "/lua/"; string[] files = Directory.GetFiles(rootPath, "*.unity3d", SearchOption.AllDirectories); ABPackHelper.ShowProgress("rename lua file...", 0); for (int i = 0; i < files.Length; ++i) { var file = files[i]; var fileName = Path.GetFileName(file); var bytes = File.ReadAllBytes(file); File.Delete(file); var newName = RenameResFileWithRandomCode(fileName) + ".unity3d"; File.WriteAllBytes(rootPath + newName, bytes); ABPackHelper.ShowProgress("rename lua file: " + fileName, (float)i / (float)files.Length); } ABPackHelper.ShowProgress("Finished...", 1); AssetDatabase.Refresh(); }
public void CopySDK() { try { string fromPath = Application.dataPath.Replace("/Assets", "") + "/Public/" + sdk_path; string toPath = Application.dataPath + "/Plugins/Android/"; if (Directory.Exists(toPath)) { Directory.Delete(toPath, true); } Directory.CreateDirectory(toPath); string[] files = Directory.GetFiles(fromPath, "*.*", SearchOption.AllDirectories); for (int i = 0; i < files.Length; ++i) { var dest = files[i].Replace("\\", "/").Replace(fromPath + "/", ""); var dirs = dest.Split('/'); string path = toPath; ABPackHelper.ShowProgress("copy sdk: " + dest, (float)i / (float)files.Length); foreach (var dir in dirs) { if (dir.Contains(".")) { continue; } path += "/" + dir; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } File.Copy(files[i], toPath + "/" + dest, true); } ABPackHelper.ShowProgress("finished...", 1); AssetDatabase.Refresh(); } catch (Exception e) { Debug.LogException(e); EditorUtility.ClearProgressBar(); } }
//递归所有C#代码 static public void LoadDiectoryCS(DirectoryInfo dictoryInfo) { if (!dictoryInfo.Exists) { return; } FileInfo[] fileInfos = dictoryInfo.GetFiles("*.cs", SearchOption.AllDirectories); int index = 0; Regex rx = new Regex("[\u4e00-\u9fa5]+"); foreach (FileInfo files in fileInfos) { ABPackHelper.ShowProgress("Check CHN in csripts", (float)index / (float)fileInfos.Length); string path = files.FullName.Replace("\\", "/"); if (path.Contains("Editor/")) { continue; } string assetPath = path.Substring(path.IndexOf("Assets/")); TextAsset textAsset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(TextAsset)) as TextAsset; string text = textAsset.text; //用正则表达式把代码里面两种字符串中间的字符串提取出来。 Regex reg = new Regex("\"[^\"]*\""); MatchCollection mc = reg.Matches(text); foreach (Match m in mc) { if (rx.IsMatch(m.Value) && (!m.Value.StartsWith("//") && !m.Value.StartsWith("/*"))) { string format = m.Value.TrimStart('"').TrimEnd('"'); if (!Localization.Contains(format) && !string.IsNullOrEmpty(format)) { Localization.Add(format); staticWriteText += format + "\n"; } } } index++; } ABPackHelper.ShowProgress("Check CHN in csripts", 1); }
//递归所有UI Prefab static public void LoadDiectoryPrefab(DirectoryInfo dictoryInfo) { if (!dictoryInfo.Exists) { return; } FileInfo[] fileInfos = dictoryInfo.GetFiles("*.prefab", SearchOption.AllDirectories); int index = 0; foreach (FileInfo files in fileInfos) { ABPackHelper.ShowProgress("Check CHN in prefabs", (float)index / (float)fileInfos.Length); string path = files.FullName.Replace("\\", "/"); string assetPath = path.Substring(path.IndexOf("Assets/")); GameObject prefab = AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)) as GameObject; GameObject instance = GameObject.Instantiate(prefab) as GameObject; SearchPrefabString(instance.transform); GameObject.DestroyImmediate(instance); index++; } ABPackHelper.ShowProgress("Check CHN in prefabs", 1); }
bool SetPlayerSavePath() { string ext = ""; string locationPath = ""; string appName = DateTime.Now.ToString("yyyyMMdd"); switch (ABPackHelper.GetBuildTarget()) { case BuildTarget.Android: ext = "apk"; locationPath = Path.Combine(Application.dataPath, "../android_apk/"); break; case BuildTarget.StandaloneWindows: case BuildTarget.StandaloneWindows64: ext = "exe"; locationPath = Path.Combine(Application.dataPath, "../win_exe/"); if (!Directory.Exists(locationPath)) { Directory.CreateDirectory(locationPath); } break; case BuildTarget.iOS: locationPath = Application.dataPath.Replace("jyjh/Assets", "") + "xcode_proj"; break; } if (!Directory.Exists(locationPath)) { Directory.CreateDirectory(locationPath); } Apk_Save_Path = EditorUtility.SaveFilePanel(ABLanguage.PACK_SAVE_FOLDER, locationPath, appName, ext); if (string.IsNullOrEmpty(Apk_Save_Path)) { return(false); } return(true); }
public static void CommitIOSCompressedData() { if (ABPackHelper.GetBuildTarget() != BuildTarget.iOS) { return; } try { string path = ABPackHelper.TEMP_ASSET_PATH + "/IOSCompress/"; var args = string.Format("/command:commit /path:{0} /logmsg:提交ios打包压缩资源", path); var p = Process.Start(TORTOISEPROC_NAME, args); p.WaitForExit(); } catch (Exception e) { EditorUtility.DisplayDialog("错误", "资源上传svn错误: " + e.Message, "OK"); } finally { AssetDatabase.Refresh(); } }
public static void InsertRandomFile() { string[] files = Directory.GetFiles(IOS_RES_PATH, "*.*", SearchOption.AllDirectories); Hashtable tbl = new Hashtable(); ABPackHelper.ShowProgress("insert random file...", 0); for (int i = 0; i < files.Length; ++i) { var path = Path.GetDirectoryName(files[i]); if (tbl.ContainsKey(path)) { continue; } tbl.Add(path, "path"); int randomNum = UnityEngine.Random.Range(30, 200); for (int j = 0; j < randomNum; ++j) { try { string str = GetRandomString(30); var save_path = Path.Combine(path, str); if (File.Exists(save_path)) { continue; } File.WriteAllBytes(save_path, Encoding.GetBytes(str)); } catch { } } ABPackHelper.ShowProgress("insert random file...", (float)i / (float)files.Length); } ABPackHelper.ShowProgress("insert random file...", 1); AssetDatabase.Refresh(); }
void BuildPlayer(bool packAllRes, bool forceUpdate) { var option = BuildOptions.None; if (debug) { option |= BuildOptions.AllowDebugging; } if (development) { option |= BuildOptions.Development; } if (autoConnectProfile) { option |= BuildOptions.ConnectWithProfiler; } var temps = Apk_Save_Path.Replace("\\", "/").Split('/'); if ((ABPackHelper.GetBuildTarget() == BuildTarget.Android || ABPackHelper.GetBuildTarget() == BuildTarget.StandaloneWindows64 || ABPackHelper.GetBuildTarget() == BuildTarget.StandaloneWindows) && sdkConfig != null) { string lastChannel = string.Empty; for (int i = 0; i < sdkConfig.items.Count; ++i) { StringBuilder final_path = new StringBuilder(); for (int j = 0; j < temps.Length - 1; ++j) { final_path.Append(temps[j] + "/"); } var item = sdkConfig.items[i]; if (item.need_subpack == 0 && !packAllRes) { continue; } if (ABPackHelper.GetBuildTarget() == BuildTarget.StandaloneWindows64 || ABPackHelper.GetBuildTarget() == BuildTarget.StandaloneWindows) { final_path.Append(DateTime.Now.ToString("yyyyMMdd") + "/"); if (!Directory.Exists(final_path.ToString())) { Directory.CreateDirectory(final_path.ToString()); } final_path.Append(item.game_name + "_v"); } else { if (packAllRes) { if (item.development == 1) { option |= BuildOptions.Development; final_path.Append(item.game_name + DateTime.Now.ToString("yyyyMMdd") + "_allpack_dev_v"); } else if (item.use_sdk == 1) { final_path.Append(item.game_name + DateTime.Now.ToString("yyyyMMdd") + "_allpack_sdk_v"); } else { final_path.Append(item.game_name + DateTime.Now.ToString("yyyyMMdd") + "_allpack_test_v"); } } else { if (item.development == 1) { option |= BuildOptions.Development; final_path.Append(item.game_name + DateTime.Now.ToString("yyyyMMdd") + "_subpack_dev_v"); } else if (item.use_sdk == 1) { final_path.Append(item.game_name + DateTime.Now.ToString("yyyyMMdd") + "_subpack_sdk_v"); } else { final_path.Append(item.game_name + DateTime.Now.ToString("yyyyMMdd") + "_subpack_test_v"); } } } final_path.Append(gameVersion.ToString()); if (ABPackHelper.GetBuildTarget() == BuildTarget.Android) { final_path.Append(".apk"); if (File.Exists(final_path.ToString())) { File.Delete(final_path.ToString()); } // 写入并保存sdk启用配置 item.CopyConfig(); item.CopySDK(); item.SetPlayerSetting(sdkConfig.splash_image); item.SaveSDKConfig(); item.SplitAssets(sdkConfig.split_assets); IncreaseLEBIAN_VERCODE(forceUpdate, item.update_along); if (item.update_along == 0 && forceUpdate) { if (Directory.Exists(Application.streamingAssetsPath)) { Directory.Delete(Application.streamingAssetsPath, true); } } } else if (ABPackHelper.GetBuildTarget() == BuildTarget.StandaloneWindows64 || ABPackHelper.GetBuildTarget() == BuildTarget.StandaloneWindows) { final_path.Append(".exe"); if (Directory.Exists(final_path.ToString())) { Directory.Delete(final_path.ToString(), true); } item.CopyConfig(); } AssetDatabase.Refresh(); BuildPipeline.BuildPlayer(ABPackHelper.GetBuildScenes(), final_path.ToString(), ABPackHelper.GetBuildTarget(), option); AssetDatabase.Refresh(); item.ClearSDK(); SVNHelper.UpdateAll(); } } else if (ABPackHelper.GetBuildTarget() == BuildTarget.iOS) { // 在上传目录新建一个ios_check.txt文件用于判断当前包是否出于提审状态 string checkFile = ABPackHelper.ASSET_PATH + LuaConst.osDir + "/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(ABPackHelper.GetBuildScenes(), Apk_Save_Path, ABPackHelper.GetBuildTarget(), option); AssetDatabase.Refresh(); } Resources.UnloadUnusedAssets(); GC.Collect(); Debug.Log("<color=green>Build success!</color>"); }
//提取lua上的中文 static public void LoadDiectoryLua(DirectoryInfo dictoryInfo) { if (!dictoryInfo.Exists) { return; } FileInfo[] fileInfos = dictoryInfo.GetFiles("*.lua", SearchOption.AllDirectories); int index = 0; Regex rx = new Regex("[\u4e00-\u9fa5]+"); List <string> chnLuaAssets = new List <string>(); foreach (FileInfo files in fileInfos) { ABPackHelper.ShowProgress("Check CHN in lua", (float)index / (float)fileInfos.Length); string path = files.FullName.Replace("\\", "/"); string assetPath = path.Substring(path.IndexOf("Assets/")); string[] lines = File.ReadAllLines(assetPath); if (assetPath.Contains("language/") || assetPath.Contains("xlsdata/") || assetPath.Contains("Setting/")) { continue; } //用正则表达式把代码里面两种字符串中间的字符串提取出来。 Regex reg = new Regex("\"[^\"]*\""); foreach (string line in lines) { MatchCollection mc = reg.Matches(line); foreach (Match m in mc) { if (rx.IsMatch(m.Value)) { string prefix = line.Substring(0, line.Length - m.Value.Length - 1); if (prefix.EndsWith("print(") || prefix.EndsWith("log(") || prefix.EndsWith("logWarning(") || prefix.EndsWith("logWarn(") || prefix.EndsWith("logError(") || prefix.EndsWith("error(")) { continue; } string format = m.Value.TrimStart('"').TrimEnd('"'); if (!Localization.Contains(format) && !string.IsNullOrEmpty(format)) { Localization.Add(format); staticWriteText += format + "\n"; if (!chnLuaAssets.Contains(assetPath)) { chnLuaAssets.Add(assetPath); } } } } } index++; } ABPackHelper.ShowProgress("Check CHN in lua", 1); string luaCHNoutPath = Application.dataPath + "/Res/I18N/lua_out.txt"; if (File.Exists(luaCHNoutPath)) { File.Delete(luaCHNoutPath); } File.WriteAllLines(luaCHNoutPath, chnLuaAssets.ToArray()); }
void ClearABName() { ABPackHelper.ClearAllAbName(); }
void CompressWithZSTD(long maxFileSize) { string outPutPath = Application.streamingAssetsPath + "/" + LuaConst.osDir; ABPackHelper.ShowProgress("Hold on...", 0); 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 = dirs[i].GetFiles("*.*", SearchOption.AllDirectories); for (int j = 0; j < abFileInfos.Length; ++j) { if (abFileInfos[j].FullName.EndsWith(".meta")) { continue; } if (curSize >= maxFileSize) { curSize = 0; tmpIndex++; } if (curSize == 0) { allFiles.Add(tmpIndex, new List <string>()); } var fileName = ABPackHelper.GetRelativeAssetsPath(abFileInfos[j].FullName); allFiles[tmpIndex].Add(fileName); curSize += File.ReadAllBytes(fileName).Length; } } int index = 0; // 合并生成的bundle文件,合成10M左右的小包(二进制) 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); ABPackHelper.ShowProgress("Streaming data...", (float)index++ / (float)allFiles.Count); using (var fs = new FileStream(savePath, FileMode.CreateNew)) { using (var writer = new BinaryWriter(fs)) { for (int i = 0; i < allFiles[key].Count; ++i) { var bytes = File.ReadAllBytes(allFiles[key][i]); var abName = allFiles[key][i].Replace("Assets/StreamingAssets/" + LuaConst.osDir + "/", ""); writer.Write(abName); writer.Write(bytes.Length); writer.Write(bytes); } } } } ABPackHelper.ShowProgress("Finished...", 1); for (int i = 0; i < dirs.Length; ++i) { if (dirs[i].Name == "lua") { continue; } Directory.Delete(dirs[i].FullName, true); } AssetDatabase.Refresh(); // 对合并后的文件进行压缩 ABPackHelper.ShowProgress("Hold on...", 0); var pakFiles = Directory.GetFiles(outPutPath, "*.tmp", SearchOption.AllDirectories); for (int i = 0; i < pakFiles.Length; ++i) { var savePath = string.Format("{0}/{1}.bin", outPutPath, Path.GetFileNameWithoutExtension(pakFiles[i])); ABPackHelper.ShowProgress("compress with zstd...", (float)i / (float)pakFiles.Length); var fileName = ABPackHelper.GetRelativeAssetsPath(pakFiles[i]); using (var compressFs = new FileStream(savePath, FileMode.CreateNew)) { using (var compressor = new Compressor(new CompressionOptions(CompressionOptions.MaxCompressionLevel))) { var bytes = compressor.Wrap(File.ReadAllBytes(fileName)); #if UNITY_IOS bytes = Crypto.Encode(bytes); #endif compressFs.Write(bytes, 0, bytes.Length); } } File.Delete(fileName); } ABPackHelper.ShowProgress("Finished...", 1); // 生成包体第一次进入游戏解压缩配置文件 StringBuilder builder = new StringBuilder(); string[] allfiles = Directory.GetFiles(outPutPath, "*.*", SearchOption.AllDirectories); for (int i = 0; i < allfiles.Length; ++i) { if (allfiles[i].EndsWith(".meta")) { continue; } if (allfiles[i].EndsWith("datamap.ab")) { continue; } var fileName = allfiles[i].Replace(outPutPath, "").Replace("\\", "/").TrimStart('/'); builder.Append(fileName); builder.Append('|'); builder.Append(MD5.ComputeHashString(allfiles[i])); builder.Append("\n"); } var packFlistPath = outPutPath + "/packlist.txt"; if (File.Exists(packFlistPath)) { File.Delete(packFlistPath); } File.WriteAllText(packFlistPath, builder.ToString()); AssetDatabase.Refresh(); }