public void OnPreprocessBuild(BuildTarget target, string path) { using (var sw = PlatDependant.OpenWriteText("Assets/StreamingAssets/res/index.txt")) { var files = PlatDependant.GetAllFiles("Assets/StreamingAssets/res/mani/"); if (files != null) { for (int i = 0; i < files.Length; ++i) { var file = files[i]; if (file.EndsWith(".m.ab")) { var key = file.Substring("Assets/StreamingAssets/res/mani/".Length, file.Length - "Assets/StreamingAssets/res/mani/".Length - ".m.ab".Length); sw.WriteLine(key); } } } } using (var sw = PlatDependant.OpenWriteText("Assets/StreamingAssets/res/builtin-scenes.txt")) { var scenes = EditorBuildSettings.scenes; int index = 0; for (int i = 0; i < scenes.Length; ++i) { var sceneinfo = scenes[i]; if (sceneinfo.enabled) { var guid = sceneinfo.guid.ToString(); var scenepath = AssetDatabase.GUIDToAssetPath(guid); sw.Write(scenepath); sw.Write("|"); sw.WriteLine(index++); } } } }
public static IEnumerator BuildResAsync(IList <string> assets, IEditorWorkProgressShower winprog, IList <IResBuilderEx> runOnceExBuilder) { bool isDefaultBuild = assets == null; var logger = new EditorWorkProgressLogger() { Shower = winprog }; bool shouldCreateBuildingParams = BuildingParams == null; BuildingParams = BuildingParams ?? ResBuilderParams.Create(); var timetoken = BuildingParams.timetoken; var makezip = BuildingParams.makezip; string outputDir = "Latest"; if (!isDefaultBuild) { outputDir = timetoken + "/build"; } outputDir = "EditorOutput/Build/" + outputDir; System.IO.StreamWriter swlog = null; try { System.IO.Directory.CreateDirectory(outputDir + "/log/"); swlog = new System.IO.StreamWriter(outputDir + "/log/ResBuildLog.txt", false, System.Text.Encoding.UTF8); } catch (Exception e) { Debug.Log(e); } EditorApplication.LockReloadAssemblies(); List <IResBuilderEx> allExBuilders = new List <IResBuilderEx>(ResBuilderEx); if (runOnceExBuilder != null) { allExBuilders.AddRange(runOnceExBuilder); } Application.LogCallback LogToFile = (message, stack, logtype) => { swlog.WriteLine(message); swlog.Flush(); }; if (swlog != null) { Application.logMessageReceived += LogToFile; } for (int i = 0; i < allExBuilders.Count; ++i) { allExBuilders[i].Prepare(outputDir); } bool cleanupDone = false; Action BuilderCleanup = () => { if (!cleanupDone) { logger.Log("(Phase) Build Res Cleaup."); cleanupDone = true; for (int i = 0; i < allExBuilders.Count; ++i) { allExBuilders[i].Cleanup(); } logger.Log("(Done) Build Res Cleaup."); if (swlog != null) { Application.logMessageReceived -= LogToFile; swlog.Flush(); swlog.Dispose(); if (isDefaultBuild) { var logdir = "EditorOutput/Build/" + timetoken + "/log/"; System.IO.Directory.CreateDirectory(logdir); System.IO.File.Copy(outputDir + "/log/ResBuildLog.txt", logdir + "ResBuildLog.txt", true); } } if (shouldCreateBuildingParams) { BuildingParams = null; } EditorApplication.UnlockReloadAssemblies(); } }; if (winprog != null) { winprog.OnQuit += BuilderCleanup; } try { logger.Log("(Start) Build Res."); if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } //logger.Log("(Phase) Ex Full Build System."); //for (int i = 0; i < allExBuilders.Count; ++i) //{ // IEnumerator exwork = allExBuilders[i].CustomBuild(); // if (exwork != null) // { // while (exwork.MoveNext()) // { // if (winprog != null) // { // yield return exwork.Current; // } // } // } // if (winprog != null && AsyncWorkTimer.Check()) yield return null; //} // Generate Build Work Dictionary <string, CapsResBuildWork> works = new Dictionary <string, CapsResBuildWork>(); var work = GenerateBuildWorkAsync(works, assets, winprog, runOnceExBuilder); while (work.MoveNext()) { if (winprog != null) { yield return(work.Current); } } logger.Log("(Phase) Write Manifest."); var managermod = CapsEditorUtils.__MOD__; var manidir = "Assets/Mods/" + managermod + "/Build/"; System.IO.Directory.CreateDirectory(manidir); List <AssetBundleBuild> listManiBuilds = new List <AssetBundleBuild>(); HashSet <string> maniFileNames = new HashSet <string>(); foreach (var kvp in works) { foreach (var mani in kvp.Value.Manifests) { var mod = mani.MFlag; var dist = mani.DFlag; if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } logger.Log("Mod " + mod + "; Dist " + dist); var dmani = CapsResManifest.Save(mani); var filename = "m-" + mod + "-d-" + dist; var manipath = manidir + filename + ".m.asset"; AssetDatabase.CreateAsset(dmani, manipath); maniFileNames.Add(filename.ToLower()); listManiBuilds.Add(new AssetBundleBuild() { assetBundleName = filename + ".m.ab", assetNames = new[] { manipath } }); } } logger.Log("(Phase) Build Manifest."); if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } var buildopt = BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.ChunkBasedCompression; BuildTarget buildtar = EditorUserBuildSettings.activeBuildTarget; var outmanidir = outputDir + "/res/mani"; System.IO.Directory.CreateDirectory(outmanidir); BuildPipeline.BuildAssetBundles(outmanidir, listManiBuilds.ToArray(), buildopt, buildtar); logger.Log("(Phase) Delete Unused Manifest."); if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } var manifiles = PlatDependant.GetAllFiles(outmanidir); for (int i = 0; i < manifiles.Length; ++i) { var file = manifiles[i]; if (file.EndsWith(".m.ab")) { var filename = file.Substring(outmanidir.Length + 1, file.Length - outmanidir.Length - 1 - ".m.ab".Length); if (!maniFileNames.Contains(filename)) { PlatDependant.DeleteFile(file); PlatDependant.DeleteFile(file + ".manifest"); } } } logger.Log("(Phase) Real Build."); foreach (var kvp in works) { var mod = kvp.Key; var abs = kvp.Value.ABs; logger.Log("Mod " + mod); if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } var dest = outputDir + "/res"; if (!string.IsNullOrEmpty(mod)) { dest += "/mod/" + mod; } System.IO.Directory.CreateDirectory(dest); // delete the unused ab HashSet <string> buildFiles = new HashSet <string>(); for (int i = 0; i < abs.Length; ++i) { if (!kvp.Value.ForceRefreshABs.Contains(i)) { if (string.IsNullOrEmpty(abs[i].assetBundleVariant)) { buildFiles.Add(abs[i].assetBundleName.ToLower()); } else { buildFiles.Add(abs[i].assetBundleName.ToLower() + "." + abs[i].assetBundleVariant.ToLower()); } } } var files = System.IO.Directory.GetFiles(dest); for (int i = 0; i < files.Length; ++i) { var file = files[i]; if (!file.EndsWith(".ab")) { var sub = System.IO.Path.GetFileName(file); var split = sub.LastIndexOf(".ab."); if (split < 0) { continue; } var ext = sub.Substring(split + ".ab.".Length); if (ext.Contains(".")) { continue; } if (ext == "manifest") { continue; } } { var fileName = System.IO.Path.GetFileName(file); if (!buildFiles.Contains(fileName)) { PlatDependant.DeleteFile(file); PlatDependant.DeleteFile(file + ".manifest"); } } } BuildPipeline.BuildAssetBundles(dest, abs, buildopt, buildtar); } logger.Log("(Phase) Delete Mod Folder Not Built."); var outmoddir = outputDir + "/res/mod/"; if (System.IO.Directory.Exists(outmoddir)) { var builtMods = new HashSet <string>(works.Keys); var allModFolders = System.IO.Directory.GetDirectories(outmoddir); int deletedModFolderCnt = 0; for (int i = 0; i < allModFolders.Length; ++i) { if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } var modfolder = allModFolders[i]; logger.Log(modfolder); var mod = modfolder.Substring(outmoddir.Length); if (!builtMods.Contains(mod)) { System.IO.Directory.Delete(modfolder, true); ++deletedModFolderCnt; } } if (deletedModFolderCnt == allModFolders.Length) { System.IO.Directory.Delete(outmoddir, true); } } if (isDefaultBuild) { logger.Log("(Phase) Write Version."); var outverdir = outputDir + "/res/version.txt"; int version = GetResVersion(); System.IO.File.WriteAllText(outverdir, version.ToString()); } logger.Log("(Phase) Copy."); var outresdir = outputDir + "/res/"; var allbuildfiles = PlatDependant.GetAllFiles(outresdir); if (System.IO.Directory.Exists("Assets/StreamingAssets/res/")) { logger.Log("Delete old."); var allexistfiles = PlatDependant.GetAllFiles("Assets/StreamingAssets/res/"); for (int i = 0; i < allexistfiles.Length; ++i) { if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } PlatDependant.DeleteFile(allexistfiles[i]); } } for (int i = 0; i < allbuildfiles.Length; ++i) { if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } var srcfile = allbuildfiles[i]; if (srcfile.EndsWith(".manifest")) { continue; } var part = srcfile.Substring(outresdir.Length); if (part == "mani/mani") { continue; } logger.Log(part); var destfile = "Assets/StreamingAssets/res/" + part; PlatDependant.CreateFolder(System.IO.Path.GetDirectoryName(destfile)); System.IO.File.Copy(srcfile, destfile); } if (System.IO.Directory.Exists("Assets/StreamingAssets/res/mod/")) { logger.Log("(Phase) Delete StreamingAssets Mod Folder Not Built."); var builtMods = new HashSet <string>(works.Keys); var allModFolders = System.IO.Directory.GetDirectories("Assets/StreamingAssets/res/mod/"); int deletedModFolderCnt = 0; for (int i = 0; i < allModFolders.Length; ++i) { if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } var modfolder = allModFolders[i]; logger.Log(modfolder); var mod = modfolder.Substring("Assets/StreamingAssets/res/mod/".Length); if (!builtMods.Contains(mod)) { System.IO.Directory.Delete(modfolder, true); ++deletedModFolderCnt; } } if (deletedModFolderCnt == allModFolders.Length) { System.IO.Directory.Delete("Assets/StreamingAssets/res/mod/", true); } } if (isDefaultBuild && makezip) { logger.Log("(Phase) Zip."); List <Pack <string, string, IList <string> > > zips = new List <Pack <string, string, IList <string> > >(); var outzipdir = "EditorOutput/Build/" + timetoken + "/whole/res/"; System.IO.Directory.CreateDirectory(outzipdir); foreach (var kvp in works) { var mod = kvp.Key; var manis = kvp.Value.Manifests; for (int i = 0; i < manis.Length; ++i) { var opmod = manis[i].MFlag; var dist = manis[i].DFlag; if (winprog != null && AsyncWorkTimer.Check()) { yield return(null); } logger.Log("Mod " + opmod + "; Dist " + dist); List <string> entries = new List <string>(); // abs var abdir = outputDir + "/res"; if (!string.IsNullOrEmpty(mod)) { abdir += "/mod/" + mod; } if (System.IO.Directory.Exists(abdir)) { try { var files = System.IO.Directory.GetFiles(abdir); for (int j = 0; j < files.Length; ++j) { var file = files[j]; if (!file.EndsWith(".ab")) { var sub = System.IO.Path.GetFileName(file); var split = sub.LastIndexOf(".ab."); if (split < 0) { continue; } var ext = sub.Substring(split + ".ab.".Length); if (ext.Contains(".")) { continue; } if (ext == "manifest") { continue; } } { var bundle = file.Substring(abdir.Length + 1); if (IsBundleInModAndDist(bundle, opmod, dist)) { var entry = file.Substring(outputDir.Length + 1); entries.Add(entry); entries.Add(entry + ".manifest"); } } } } catch (Exception e) { logger.Log("(Error)(Not Critical)"); logger.Log(e.ToString()); } } if (entries.Count > 0) { // unity build mani var umani = abdir + "/" + (string.IsNullOrEmpty(mod) ? "res" : mod); umani = umani.Substring(outputDir.Length + 1); entries.Add(umani); entries.Add(umani + ".manifest"); // mani var mani = "m-" + opmod.ToLower() + "-d-" + dist.ToLower() + ".m.ab"; mani = "res/mani/" + mani; entries.Add(mani); entries.Add(mani + ".manifest"); entries.Add("res/mani/mani"); entries.Add("res/mani/mani.manifest"); // version entries.Add("res/version.txt"); var zipfile = outzipdir + "m-" + opmod + "-d-" + dist + ".zip"; zips.Add(new Pack <string, string, IList <string> >(zipfile, outputDir, entries)); //var workz = MakeZipAsync(zipfile, outputDir, entries, winprog); //while (workz.MoveNext()) //{ // if (winprog != null) // { // yield return workz.Current; // } //} } } } if (zips.Count > 0) { var workz = CapsResBuilder.MakeZipsBackground(zips, winprog); while (workz.MoveNext()) { if (winprog != null) { yield return(workz.Current); } } } } for (int i = 0; i < allExBuilders.Count; ++i) { allExBuilders[i].OnSuccess(); } } finally { BuilderCleanup(); logger.Log("(Done) Build Res."); } }
private static void LoadRuntimeManifest(TaskProgress progress) { try { var maniPath = ThreadSafeValues.UpdatePath + "/spt/manifest.m.txt"; if (PlatDependant.IsFileExist(maniPath)) { _RuntimeRawManifest = LoadManifest(maniPath); } else { CapsResManifest mani = new CapsResManifest(); // load from update path var sptfolder = ThreadSafeValues.UpdatePath + "/spt/"; try { var files = PlatDependant.GetAllFiles(sptfolder); if (files != null && files.Length > 0) { for (int i = 0; i < files.Length; ++i) { var file = files[i]; var part = file.Substring(sptfolder.Length).Replace('\\', '/'); var node = mani.AddOrGetItem(part); if (node.Item == null) { CapsResManifestItem item; item = new CapsResManifestItem(node); node.Item = item; } } } } catch (Exception e) { PlatDependant.LogError(e); } // load from package if (ThreadSafeValues.AppStreamingAssetsPath.Contains("://")) { if (ThreadSafeValues.AppPlatform == RuntimePlatform.Android.ToString() && ResManager.LoadAssetsFromApk) { // Obb if (ResManager.LoadAssetsFromObb && ResManager.ObbZipArchive != null) { sptfolder = "spt/"; int retryTimes = 10; int entryindex = 0; for (int i = 0; i < retryTimes; ++i) { Exception error = null; do { ZipArchive za = ResManager.ObbZipArchive; if (za == null) { PlatDependant.LogError("Obb Archive Cannot be read."); break; } try { var entries = za.Entries; while (entryindex < entries.Count) { var entry = entries[entryindex]; var fullname = entry.FullName; if (fullname.StartsWith(sptfolder)) { var part = fullname.Substring(sptfolder.Length); var node = mani.AddOrGetItem(part); if (node.Item == null) { CapsResManifestItem item; item = new CapsResManifestItem(node); node.Item = item; } } ++entryindex; } } catch (Exception e) { error = e; break; } } while (false); if (error != null) { if (i == retryTimes - 1) { PlatDependant.LogError(error); } else { PlatDependant.LogError(error); PlatDependant.LogInfo("Need Retry " + i); } } else { break; } } } // Apk //if (true) { sptfolder = "assets/spt/"; int retryTimes = 10; int entryindex = 0; for (int i = 0; i < retryTimes; ++i) { Exception error = null; do { ZipArchive za = ResManager.AndroidApkZipArchive; if (za == null) { PlatDependant.LogError("Apk Archive Cannot be read."); break; } try { var entries = za.Entries; while (entryindex < entries.Count) { var entry = entries[entryindex]; var fullname = entry.FullName; if (fullname.StartsWith(sptfolder)) { var part = fullname.Substring(sptfolder.Length); var node = mani.AddOrGetItem(part); if (node.Item == null) { CapsResManifestItem item; item = new CapsResManifestItem(node); node.Item = item; } } ++entryindex; } } catch (Exception e) { error = e; break; } } while (false); if (error != null) { if (i == retryTimes - 1) { PlatDependant.LogError(error); } else { PlatDependant.LogError(error); PlatDependant.LogInfo("Need Retry " + i); } } else { break; } } } } } else { sptfolder = ThreadSafeValues.AppStreamingAssetsPath + "/spt/"; try { var files = PlatDependant.GetAllFiles(sptfolder); if (files != null && files.Length > 0) { for (int i = 0; i < files.Length; ++i) { var file = files[i]; var part = file.Substring(sptfolder.Length).Replace('\\', '/'); var node = mani.AddOrGetItem(part); if (node.Item == null) { CapsResManifestItem item; item = new CapsResManifestItem(node); node.Item = item; } } } } catch (Exception e) { PlatDependant.LogError(e); } } mani.TrimExcess(); _RuntimeRawManifest = mani; _RuntimeManifestReady.Set(); SaveManifest(mani, maniPath); } } finally { _RuntimeManifestReady.Set(); _RuntimeManifestTaskIdle.Set(); } }
public static IEnumerator BuildAllUpdateWork(string olddir, string newdir, string diffdir, IEditorWorkProgressShower winprog) { olddir = (olddir ?? ".").TrimEnd('/', '\\'); newdir = (newdir ?? ".").TrimEnd('/', '\\'); diffdir = (diffdir ?? ".").TrimEnd('/', '\\'); var logger = new EditorWorkProgressLogger() { Shower = winprog }; System.IO.StreamWriter swlog = null; try { System.IO.Directory.CreateDirectory(diffdir); swlog = new System.IO.StreamWriter(diffdir + "/UpdateBuildLog.txt", false, System.Text.Encoding.UTF8); } catch (Exception e) { UnityEngine.Debug.Log(e); } UnityEngine.Application.LogCallback LogToFile = (message, stack, logtype) => { swlog.WriteLine(message); swlog.Flush(); }; if (swlog != null) { UnityEngine.Application.logMessageReceived += LogToFile; } bool cleanupDone = false; Action BuilderCleanup = () => { if (!cleanupDone) { logger.Log("(Phase) Build Update Cleaup."); cleanupDone = true; logger.Log("(Done) Build Update Cleaup."); if (swlog != null) { UnityEngine.Application.logMessageReceived -= LogToFile; swlog.Flush(); swlog.Dispose(); } } }; if (winprog != null) winprog.OnQuit += BuilderCleanup; try { logger.Log("Build Res Update"); { var subdir = "/res/"; var oroot = olddir + subdir; var nroot = newdir + subdir; var droot = diffdir + subdir; var nfiles = PlatDependant.GetAllFiles(nroot); for (int i = 0; i < nfiles.Length; ++i) { var nfile = nfiles[i]; if (nfile.EndsWith(".zip")) { nfile = nfile.Substring(nroot.Length); logger.Log(nfile); if (BuildResUpdate(oroot + nfile, nroot + nfile, droot + nfile)) { logger.Log("Done: " + nfile); } else { logger.Log("No diff: " + nfile); } if (winprog != null && AsyncWorkTimer.Check()) yield return null; } } } logger.Log("Build Spt Update"); { var subdir = "/spt/"; var oroot = olddir + subdir; var nroot = newdir + subdir; var droot = diffdir + subdir; var nfiles = PlatDependant.GetAllFiles(nroot); for (int i = 0; i < nfiles.Length; ++i) { var nfile = nfiles[i]; if (nfile.EndsWith(".zip")) { nfile = nfile.Substring(nroot.Length); logger.Log(nfile); if (BuildSptUpdate(oroot + nfile, nroot + nfile, droot + nfile)) { logger.Log("Done: " + nfile); } else { logger.Log("No diff: " + nfile); } if (winprog != null && AsyncWorkTimer.Check()) yield return null; } } } } finally { BuilderCleanup(); logger.Log("(Done) Build Update."); } }