public static void BuildAllFullWithProg() { CapsResBuilder.BuildingParams = CapsResBuilder.ResBuilderParams.Create(); var winprog = new EditorWorkProgressShowerInConsole(); winprog.Works.Add(CapsSptBuilder.BuildSptAsync(null, winprog)); winprog.Works.Add(CapsResBuilder.BuildResAsync(null, winprog)); winprog.Works.Add(CapsUpdateBuilder.BuildNearestUpdate(winprog)); winprog.OnQuit += () => { CapsResBuilder.BuildingParams = null; }; winprog.StartWork(); }
public static void BuildResCommand() { CapsResBuilder.BuildingParams = CapsResBuilder.ResBuilderParams.Create(); CapsResBuilder.BuildingParams.makezip = false; var work = CapsResBuilder.BuildResAsync(null, null); while (work.MoveNext()) { ; } CapsResBuilder.BuildingParams = null; }
public static void BuildAllFull() { CapsResBuilder.BuildingParams = CapsResBuilder.ResBuilderParams.Create(); var work = CapsSptBuilder.BuildSptAsync(null, null); while (work.MoveNext()) { ; } work = CapsResBuilder.BuildResAsync(null, null); while (work.MoveNext()) { ; } CapsResBuilder.BuildingParams = null; CapsUpdateBuilder.BuildNearestUpdate(); }
public static void BuildAllQuick() { CapsResBuilder.BuildingParams = CapsResBuilder.ResBuilderParams.Create(); CapsResBuilder.BuildingParams.makezip = false; var work = CapsSptBuilder.BuildSptAsync(null, null, new[] { new CapsSptBuilder.SptBuilderEx_RawCopy() }); while (work.MoveNext()) { ; } work = CapsResBuilder.BuildResAsync(null, null); while (work.MoveNext()) { ; } CapsResBuilder.BuildingParams = null; }
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."); } }
public static void CheckRes(string output) { // generate build work List <CapsResBuilder.IResBuilderEx> allExBuilders = CapsResBuilder.ResBuilderEx; for (int i = 0; i < allExBuilders.Count; ++i) { allExBuilders[i].Prepare(null); } Dictionary <string, CapsResBuilder.CapsResBuildWork> buildwork = new Dictionary <string, CapsResBuilder.CapsResBuildWork>(); var gwork = CapsResBuilder.GenerateBuildWorkAsync(buildwork, null, null); while (gwork.MoveNext()) { ; } for (int i = 0; i < allExBuilders.Count; ++i) { allExBuilders[i].Cleanup(); } // parse asset list in each reskey (m-XXX-d-YYY) Dictionary <string, List <string> > reskey2assetlist = new Dictionary <string, List <string> >(); Dictionary <string, string> asset2reskey = new Dictionary <string, string>(); HashSet <string> nodepassets = new HashSet <string>(); foreach (var buildmodwork in buildwork) { var mod = buildmodwork.Key; var work = buildmodwork.Value; var manifests = work.Manifests; for (int i = 0; i < manifests.Length; ++i) { var mani = manifests[i]; var opmod = mani.MFlag; var dist = mani.DFlag ?? ""; var reskey = "m-" + opmod + "-d-" + dist; List <string> list; if (!reskey2assetlist.TryGetValue(reskey, out list)) { list = new List <string>(); reskey2assetlist[reskey] = list; } for (int j = 0; j < work.ABs.Length; ++j) { var abinfo = work.ABs[j]; var abname = abinfo.assetBundleName; if (abname.EndsWith(".=.ab")) { for (int k = 0; k < abinfo.assetNames.Length; ++k) { var asset = abinfo.assetNames[k]; nodepassets.Add(asset); } continue; } if (!string.IsNullOrEmpty(abinfo.assetBundleVariant)) { abname += "." + abinfo.assetBundleVariant; } if (CapsResBuilder.IsBundleInModAndDist(abname, opmod, dist)) { list.AddRange(abinfo.assetNames); for (int k = 0; k < abinfo.assetNames.Length; ++k) { var asset = abinfo.assetNames[k]; asset2reskey[asset] = reskey; } } } } } // parse dep and ref Dictionary <string, HashSet <string> > resdep = new Dictionary <string, HashSet <string> >(); Dictionary <string, HashSet <string> > resref = new Dictionary <string, HashSet <string> >(); foreach (var kvpassetreskey in asset2reskey) { var asset = kvpassetreskey.Key; //var reskey = kvpassetreskey.Value; HashSet <string> deplist; if (!resdep.TryGetValue(asset, out deplist)) { deplist = new HashSet <string>(); resdep[asset] = deplist; } var deps = GetDependencies(asset); for (int i = 0; i < deps.Length; ++i) { var dep = deps[i]; deplist.Add(dep); HashSet <string> reflist; if (!resref.TryGetValue(dep, out reflist)) { reflist = new HashSet <string>(); resref[dep] = reflist; } reflist.Add(asset); } } using (var sw = PlatDependant.OpenWriteText(output)) { // check cross mod/dist ref bool crossdepfound = false; foreach (var kvpdep in resdep) { var asset = kvpdep.Key; var deps = kvpdep.Value; var assetkey = asset2reskey[asset]; foreach (var dep in deps) { if (!asset2reskey.ContainsKey(dep)) { continue; // not in build? check later. } var depkey = asset2reskey[dep]; if (assetkey == depkey) { continue; // the same package } else if (depkey == "m--d-") { continue; // any asset can refer the assets in main package. } else if (depkey.EndsWith("-d-") && assetkey.StartsWith(depkey)) { continue; // the dist package refer non-dist package. } else if (depkey.StartsWith("m--d-") && assetkey.EndsWith(depkey.Substring(2))) { continue; // the mod package refer non-mod package. } else { if (!crossdepfound) { crossdepfound = true; sw.WriteLine("Cross mod/dist reference found! See below:"); } sw.Write(asset); sw.Write(" ("); sw.Write(assetkey); sw.Write(") -> "); sw.Write(dep); sw.Write(" ("); sw.Write(depkey); sw.Write(")"); sw.WriteLine(); } } } if (!crossdepfound) { sw.WriteLine("No cross mod/dist reference found."); } // check non build dep sw.WriteLine(); bool nonbuilddepfound = false; foreach (var kvpdep in resdep) { var asset = kvpdep.Key; var deps = kvpdep.Value; foreach (var dep in deps) { if (!asset2reskey.ContainsKey(dep) && !nodepassets.Contains(dep)) { if (dep.StartsWith("Assets/") || dep.StartsWith("Packages/") && !string.IsNullOrEmpty(CapsModEditor.GetAssetModName(dep))) { if (!nonbuilddepfound) { nonbuilddepfound = true; sw.WriteLine("Non build dependency found! See below:"); } sw.Write(asset); sw.Write(" -> "); sw.Write(dep); sw.WriteLine(); } } } } if (!nonbuilddepfound) { sw.WriteLine("No non build dependency found."); } } EditorUtility.OpenWithDefaultApp(output); }