Example #1
0
 public static void StartLoadRuntimeManifest()
 {
     _RuntimeRawManifest = null;
     _RuntimeManifest    = null;
     _RuntimeManifestReady.Reset();
     _RuntimeManifestTaskIdle.Reset();
     PlatDependant.RunBackground(LoadRuntimeManifest);
 }
Example #2
0
 public static void CheckRuntimeManifest()
 {
     _RuntimeManifestReady.WaitOne();
     if (_RuntimeRawManifest == null)
     {
         StartLoadRuntimeManifest();
         _RuntimeManifestReady.WaitOne();
     }
     _RuntimeManifest = MergeAndCollapseRuntimeManifest(_RuntimeRawManifest);
 }
Example #3
0
        private static void MergeRuntimeManifestInMod(CapsResManifest target, CapsResManifestNode root)
        {
            var flags = ResManager.GetValidDistributeFlags();

            if (root.Children != null)
            {
                CapsResManifestNode modNode;
                if (root.Children.TryGetValue("mod", out modNode))
                {
                    if (modNode != null && modNode.Children != null)
                    {
                        var modChildren = modNode.Children;
                        // merge - critical mod
                        for (int i = 0; i < modChildren.Count; ++i)
                        {
                            var modChild = modChildren.Values[i];
                            var mod      = modChild.PPath;
                            var moddesc  = ResManager.GetDistributeDesc(mod);
                            if (moddesc == null || (moddesc.InMain && !moddesc.IsOptional))
                            {
                                CapsResManifest.MergeManifestNode(target.Root, modChild, true);
                            }
                        }
                        // merge - opt mod
                        for (int i = 0; i < flags.Length; ++i)
                        {
                            var flag = flags[i];
                            CapsResManifestNode modChild;
                            if (modChildren.TryGetValue(flag, out modChild))
                            {
                                if (modChild != null)
                                {
                                    CapsResManifest.MergeManifestNode(target.Root, modChild, true);
                                }
                            }
                        }
                    }
                }
            }
        }
Example #4
0
        public static void SaveManifest(CapsResManifest mani, string file)
        {
            var tmpfile = file + ".tmp";

            using (var sw = PlatDependant.OpenWriteText(tmpfile))
            {
                if (mani != null && mani.Root != null)
                {
                    Stack <Pack <int, CapsResManifestNode> > candis = new Stack <Pack <int, CapsResManifestNode> >();
                    candis.Push(new Pack <int, CapsResManifestNode>(0, mani.Root));
                    while (candis.Count > 0)
                    {
                        var ppair  = candis.Pop();
                        var plvl   = ppair.t1;
                        var parent = ppair.t2;

                        for (int i = 0; i < plvl; ++i)
                        {
                            sw.Write("*");
                        }
                        sw.WriteLine(parent.PPath ?? "");

                        var children = parent.Children;
                        if (children != null)
                        {
                            var clvl = plvl + 1;
                            for (int i = children.Count - 1; i >= 0; --i)
                            {
                                var child = children.Values[i];
                                candis.Push(new Pack <int, CapsResManifestNode>(clvl, child));
                            }
                        }
                    }
                }
            }
            PlatDependant.MoveFile(tmpfile, file);
        }
        public static IEnumerator GenerateBuildWorkAsync(Dictionary <string, CapsResBuildWork> result, IList <string> assets, IEditorWorkProgressShower winprog, IList <IResBuilderEx> runOnceExBuilder)
        {
            var logger = new EditorWorkProgressLogger()
            {
                Shower = winprog
            };

            logger.Log("(Start) Generate Build Work.");
            if (winprog != null && AsyncWorkTimer.Check())
            {
                yield return(null);
            }

            if (result == null)
            {
                logger.Log("(Error) You have to provide container to retrive the result.");
                yield break;
            }
            result.Clear();

            if (assets == null)
            {
                logger.Log("(Option) Get All Assets.");
                assets = AssetDatabase.GetAllAssetPaths();
                if (winprog != null && AsyncWorkTimer.Check())
                {
                    yield return(null);
                }
            }

            if (assets != null)
            {
                List <IResBuilderEx> allExBuilders = new List <IResBuilderEx>(ResBuilderEx);
                if (runOnceExBuilder != null)
                {
                    allExBuilders.AddRange(runOnceExBuilder);
                }

                Dictionary <string, Dictionary <string, List <string> > >  mod2build = new Dictionary <string, Dictionary <string, List <string> > >();
                Dictionary <string, Dictionary <string, CapsResManifest> > mod2mani  = new Dictionary <string, Dictionary <string, CapsResManifest> >();
                for (int i = 0; i < assets.Count; ++i)
                {
                    if (winprog != null && AsyncWorkTimer.Check())
                    {
                        yield return(null);
                    }
                    var asset = assets[i];
                    logger.Log(asset);

                    if (string.IsNullOrEmpty(asset))
                    {
                        logger.Log("Empty Path.");
                        continue;
                    }
                    if (System.IO.Directory.Exists(asset))
                    {
                        logger.Log("Folder.");
                        continue;
                    }
                    if (CapsResInfoEditor.IsAssetScript(asset))
                    {
                        logger.Log("Script.");
                        continue;
                    }

                    string mod       = null;
                    string opmod     = null;
                    string dist      = null;
                    string norm      = asset;
                    bool   inPackage = false;
                    if (asset.StartsWith("Assets/Mods/") || (inPackage = asset.StartsWith("Packages/")))
                    {
                        string sub;
                        if (inPackage)
                        {
                            sub = asset.Substring("Packages/".Length);
                        }
                        else
                        {
                            sub = asset.Substring("Assets/Mods/".Length);
                        }
                        var index = sub.IndexOf('/');
                        if (index < 0)
                        {
                            logger.Log("Cannot Parse Module.");
                            continue;
                        }
                        mod = sub.Substring(0, index);
                        if (inPackage)
                        {
                            mod = CapsModEditor.GetPackageModName(mod);
                        }
                        if (string.IsNullOrEmpty(mod))
                        {
                            logger.Log("Empty Module.");
                            continue;
                        }
                        sub = sub.Substring(index + 1);
                        if (!sub.StartsWith("CapsRes/"))
                        {
                            logger.Log("Should Ignore This Asset.");
                            continue;
                        }
                        var  moddesc       = ResManager.GetDistributeDesc(mod);
                        bool isMainPackage = inPackage && !CapsModEditor.ShouldTreatPackageAsMod(CapsModEditor.GetPackageName(mod));
                        if (moddesc == null || moddesc.InMain || isMainPackage)
                        {
                            mod = "";
                            if (moddesc != null && moddesc.IsOptional && !isMainPackage)
                            {
                                opmod = moddesc.Mod;
                            }
                        }

                        sub  = sub.Substring("CapsRes/".Length);
                        norm = sub;
                        if (sub.StartsWith("dist/"))
                        {
                            sub   = sub.Substring("dist/".Length);
                            index = sub.IndexOf('/');
                            if (index > 0)
                            {
                                dist = sub.Substring(0, index);
                                norm = sub.Substring(index + 1);
                            }
                        }
                    }
                    else
                    {
                        if (asset.StartsWith("Assets/CapsRes/"))
                        {
                            mod = "";
                            var sub = asset.Substring("Assets/CapsRes/".Length);
                            norm = sub;
                            if (sub.StartsWith("dist/"))
                            {
                                sub = sub.Substring("dist/".Length);
                                var index = sub.IndexOf('/');
                                if (index > 0)
                                {
                                    dist = sub.Substring(0, index);
                                    norm = sub.Substring(index + 1);
                                }
                            }
                        }
                        else
                        {
                            logger.Log("Should Ignore This Asset.");
                            continue;
                        }
                    }

                    if (string.IsNullOrEmpty(norm))
                    {
                        logger.Log("Normallized Path Empty.");
                        continue;
                    }
                    mod  = mod ?? "";
                    dist = dist ?? "";
                    logger.Log("Mod " + mod + "; Dist " + dist + "; Norm " + norm);

                    Dictionary <string, List <string> > builds;
                    if (!mod2build.TryGetValue(mod, out builds))
                    {
                        builds         = new Dictionary <string, List <string> >();
                        mod2build[mod] = builds;
                    }

                    Dictionary <string, CapsResManifest> manis;
                    if (!mod2mani.TryGetValue(opmod ?? mod, out manis))
                    {
                        manis = new Dictionary <string, CapsResManifest>();
                        mod2mani[opmod ?? mod] = manis;
                    }
                    CapsResManifest mani;
                    if (!manis.TryGetValue(dist, out mani))
                    {
                        mani       = new CapsResManifest();
                        mani.MFlag = opmod ?? mod;
                        mani.DFlag = dist;
                        if (opmod != null)
                        {
                            mani.InMain = true;
                        }
                        manis[dist] = mani;
                    }

                    string bundle          = null;
                    bool   shouldWriteBRef = false;
                    for (int j = 0; j < allExBuilders.Count; ++j)
                    {
                        bundle = allExBuilders[j].FormatBundleName(asset, opmod ?? mod, dist, norm);
                        if (bundle != null)
                        {
                            break;
                        }
                    }
                    if (bundle == null)
                    {
                        bundle = FormatBundleName(asset, opmod ?? mod, dist, norm);
                    }
                    else
                    {
                        shouldWriteBRef = true;
                    }

                    List <string> build;
                    if (!builds.TryGetValue(bundle, out build))
                    {
                        build          = new List <string>();
                        builds[bundle] = build;
                    }
                    build.Add(asset);

                    var node = mani.AddOrGetItem(asset);
                    for (int j = 0; j < allExBuilders.Count; ++j)
                    {
                        if (allExBuilders[j].CreateItem(node))
                        {
                            break;
                        }
                    }
                    if (node.Item == null)
                    {
                        var item = new CapsResManifestItem(node);
                        if (asset.EndsWith(".prefab"))
                        {
                            item.Type = (int)CapsResManifestItemType.Prefab;
                        }
                        else if (asset.EndsWith(".unity"))
                        {
                            item.Type = (int)CapsResManifestItemType.Scene;
                        }
                        else
                        {
                            item.Type = (int)CapsResManifestItemType.Normal;
                        }
                        if (shouldWriteBRef)
                        {
                            item.BRef = bundle;
                        }
                        node.Item = item;
                    }
                    for (int j = 0; j < allExBuilders.Count; ++j)
                    {
                        allExBuilders[j].ModifyItem(node.Item);
                    }
                }

                if (winprog != null && AsyncWorkTimer.Check())
                {
                    yield return(null);
                }
                logger.Log("(Phase) Combine the final result.");

                foreach (var kvpbuild in mod2build)
                {
                    var mod               = kvpbuild.Key;
                    var builds            = kvpbuild.Value;
                    CapsResBuildWork work = new CapsResBuildWork();
                    if (mod == "")
                    {
                        List <CapsResManifest> manis = new List <CapsResManifest>(mod2mani[mod].Values);
                        foreach (var kvpmm in mod2mani)
                        {
                            if (!mod2build.ContainsKey(kvpmm.Key))
                            {
                                manis.AddRange(kvpmm.Value.Values);
                            }
                        }
                        work.Manifests = manis.ToArray();
                    }
                    else
                    {
                        work.Manifests = mod2mani[mod].Values.ToArray();
                    }

                    work.ABs = new AssetBundleBuild[builds.Count];
                    int index = 0;
                    foreach (var kvpbundle in builds)
                    {
                        var bundleName         = kvpbundle.Key;
                        var bundleAssets       = kvpbundle.Value;
                        AssetBundleBuild build = new AssetBundleBuild();
                        build.assetBundleName = kvpbundle.Key;
                        build.assetNames      = kvpbundle.Value.ToArray();
                        for (int j = 0; j < allExBuilders.Count; ++j)
                        {
                            allExBuilders[j].GenerateBuildWork(bundleName, bundleAssets, ref build, work, index);
                        }
                        work.ABs[index++] = build;
                    }

                    result[mod] = work;
                }
            }

            logger.Log("(Done) Generate Build Work.");
        }
        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.");
            }
        }
Example #7
0
        // This will judge whether a mod is optional, so this should be called in UnityMain thread.
        private static CapsResManifest MergeAndCollapseRuntimeManifest(CapsResManifest rawmani)
        {
            var root  = rawmani.Root;
            var rmani = new CapsResManifest();

            if (root != null)
            {
                rmani.Root = new CapsResManifestNode(rmani);
                CapsResManifestNode tmpNode  = new CapsResManifestNode(rawmani);
                CapsResManifestNode archNode = null;
                if (root.Children != null)
                {
                    tmpNode.Children = new SortedList <string, CapsResManifestNode>();
                    for (int i = 0; i < root.Children.Count; ++i)
                    {
                        var child = root.Children.Values[i];
                        if (child.PPath == "mod")
                        {
                            continue;
                        }
                        else if (child.PPath == "@64")
                        {
                            if (Environment.Is64BitProcess)
                            {
                                archNode = child;
                            }
                            continue;
                        }
                        else if (child.PPath == "@32")
                        {
                            if (!Environment.Is64BitProcess)
                            {
                                archNode = child;
                            }
                            continue;
                        }
                        tmpNode.Children[child.PPath] = child;
                    }
                }
                // merge - no mod
                CapsResManifest.MergeManifestNode(rmani.Root, tmpNode, true);
                // merge - no mod on arch
                if (archNode != null)
                {
                    tmpNode = new CapsResManifestNode(rawmani);
                    if (archNode.Children != null)
                    {
                        tmpNode.Children = new SortedList <string, CapsResManifestNode>();
                        for (int i = 0; i < archNode.Children.Count; ++i)
                        {
                            var child = archNode.Children.Values[i];
                            if (child.PPath == "mod")
                            {
                                continue;
                            }
                            tmpNode.Children[child.PPath] = child;
                        }
                    }
                    CapsResManifest.MergeManifestNode(rmani.Root, tmpNode, true);
                }
                // merge - mod
                MergeRuntimeManifestInMod(rmani, root);
                // merge - mod on arch
                if (archNode != null)
                {
                    MergeRuntimeManifestInMod(rmani, archNode);
                }
                // Collapse
                var flags = ResManager.GetValidDistributeFlags();
                rmani.CollapseManifest(flags);
                rmani.TrimExcess();
            }
            return(rmani);
        }
Example #8
0
        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();
            }
        }
Example #9
0
        public static CapsResManifest LoadManifest(string file)
        {
            CapsResManifest mani = new CapsResManifest();

            if (PlatDependant.IsFileExist(file))
            {
                using (var sr = PlatDependant.OpenReadText(file))
                {
                    if (sr != null)
                    {
                        List <CapsResManifestNode> nodeStack = new List <CapsResManifestNode>();
                        var root = new CapsResManifestNode(mani);
                        mani.Root = root;
                        nodeStack.Add(root);

                        int nxtChar = -1;
                        while ((nxtChar = sr.Peek()) > 0)
                        {
                            int lvl = 0;
                            while (nxtChar == '*')
                            {
                                sr.Read();
                                ++lvl;
                                nxtChar = sr.Peek();
                            }
                            string ppath = sr.ReadLine();
                            if (string.IsNullOrEmpty(ppath))
                            {
                                continue;
                            }

                            if (nodeStack.Count > lvl)
                            {
                                var last = nodeStack[nodeStack.Count - 1];
                                if (last.Children == null || last.Children.Count <= 0)
                                {
                                    CapsResManifestItem item;
                                    item      = new CapsResManifestItem(last);
                                    last.Item = item;
                                }

                                nodeStack.RemoveRange(lvl, nodeStack.Count - lvl);
                            }

                            {
                                var last = nodeStack[nodeStack.Count - 1];
                                if (last.Children == null)
                                {
                                    last.Children = new SortedList <string, CapsResManifestNode>();
                                }
                                var child = new CapsResManifestNode(last, ppath);
                                last.Children[ppath] = child;
                                nodeStack.Add(child);
                            }
                        }

                        if (nodeStack.Count > 1)
                        {
                            var last = nodeStack[nodeStack.Count - 1];
                            CapsResManifestItem item;
                            item      = new CapsResManifestItem(last);
                            last.Item = item;
                        }

                        mani.TrimExcess();
                    }
                }
            }
            return(mani);
        }
Example #10
0
        public static bool BuildResUpdate(string oldz, string newz, string diff)
        {
            LinkedList<IDisposable> lstToDispose = new LinkedList<IDisposable>();
            try
            {
                ZipArchive olda = null, newa = null, diffa = null;

                try
                {
                    var olds = File.OpenRead(oldz);
                    lstToDispose.AddFirst(olds);
                    olda = new ZipArchive(olds, ZipArchiveMode.Read);
                    lstToDispose.AddFirst(olda);
                }
                catch { }
                try
                {
                    var news = File.OpenRead(newz);
                    lstToDispose.AddFirst(news);
                    newa = new ZipArchive(news, ZipArchiveMode.Read);
                    lstToDispose.AddFirst(newa);
                }
                catch { }

                HashSet<string> diffb = new HashSet<string>();
                if (newa == null)
                {
                    return false;
                }
                else if (Path.GetFileNameWithoutExtension(oldz) != Path.GetFileNameWithoutExtension(newz))
                {
                    PlatDependant.LogError("Build update diff error - the old zip and new zip have different names.");
                    return false;
                }
                else
                {
                    string mentry = "res/mani/" + Path.GetFileNameWithoutExtension(newz).ToLower() + ".m.ab";
                    CapsResManifest mold = null;
                    CapsResManifest mnew = null;

                    // get mani of old
                    try
                    {
                        if (olda != null)
                        {
                            var oldme = olda.GetEntry(mentry);
                            if (oldme != null)
                            {
                                using (var stream = oldme.Open())
                                {
                                    using (var mems = new MemoryStream())
                                    {
                                        stream.CopyTo(mems);
                                        var mab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                        if (mab)
                                        {
                                            var allassets = mab.LoadAllAssets<CapsResOnDiskManifest>();
                                            if (allassets != null && allassets.Length > 0)
                                            {
                                                mold = CapsResManifest.Load(allassets[0]);
                                            }
                                            mab.Unload(true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    // get mani of new
                    try
                    {
                        var newme = newa.GetEntry(mentry);
                        if (newme != null)
                        {
                            using (var stream = newme.Open())
                            {
                                using (var mems = new MemoryStream())
                                {
                                    stream.CopyTo(mems);
                                    var mab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                    if (mab)
                                    {
                                        var allassets = mab.LoadAllAssets<CapsResOnDiskManifest>();
                                        if (allassets != null && allassets.Length > 0)
                                        {
                                            mnew = CapsResManifest.Load(allassets[0]);
                                        }
                                        mab.Unload(true);
                                    }
                                }
                            }
                        }
                    }
                    catch { }

                    string abrootold = "res/";
                    string umpathold = "res/res";
                    if (mold != null && !string.IsNullOrEmpty(mold.MFlag))
                    {
                        abrootold += "mod/" + mold.MFlag + "/";
                        umpathold = abrootold + mold.MFlag;
                    }
                    string abrootnew = "res/";
                    string umpathnew = "res/res";
                    if (mnew != null && !string.IsNullOrEmpty(mnew.MFlag))
                    {
                        abrootnew += "mod/" + mnew.MFlag + "/";
                        umpathnew = abrootnew + mnew.MFlag;
                    }

                    // parse old manifest
                    UnityEngine.AssetBundleManifest maniold = null;
                    try
                    {
                        if (olda != null)
                        {
                            var emani = olda.GetEntry(umpathold);
                            if (emani != null)
                            {
                                using (var smani = emani.Open())
                                {
                                    using (var mems = new MemoryStream())
                                    {
                                        smani.CopyTo(mems);
                                        var resab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                        if (resab)
                                        {
                                            var allassets = resab.LoadAllAssets<UnityEngine.AssetBundleManifest>();
                                            if (allassets != null && allassets.Length > 0)
                                            {
                                                maniold = allassets[0];
                                                if (maniold)
                                                {
                                                    maniold = Object.Instantiate(maniold);
                                                }
                                            }
                                            resab.Unload(true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    // parse new manifest
                    UnityEngine.AssetBundleManifest maninew = null;
                    try
                    {
                        var emani = newa.GetEntry(umpathnew);
                        if (emani != null)
                        {
                            using (var smani = emani.Open())
                            {
                                using (var mems = new MemoryStream())
                                {
                                    smani.CopyTo(mems);
                                    var resab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                    if (resab)
                                    {
                                        var allassets = resab.LoadAllAssets<UnityEngine.AssetBundleManifest>();
                                        if (allassets != null && allassets.Length > 0)
                                        {
                                            maninew = allassets[0];
                                            if (maninew != null)
                                            {
                                                maninew = Object.Instantiate(maninew);
                                            }
                                        }
                                        resab.Unload(true);
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    // both manifest found?
                    if (maninew == null)
                    {
                        File.Copy(newz, diff, true);
                        return true;
                    }

                    // parse diff assets and bundles
                    if (maninew != null)
                    {
                        var allbundles = maninew.GetAllAssetBundles();
                        foreach (var bundle in allbundles)
                        {
                            var newe = newa.GetEntry(abrootnew + bundle);
                            if (newe == null)
                            {
                                continue;
                            }
                            if (maniold != null && maninew.GetAssetBundleHash(bundle) == maniold.GetAssetBundleHash(bundle))
                            {
                                if (olda != null)
                                {
                                    var olde = olda.GetEntry(abrootold + bundle);
                                    if (olde != null)
                                    {
                                        if (olde.Length == newe.Length)
                                        {
                                            // TODO: sometimes the AssetBundleHash may be same (example: we deleted a sprite-atlas).
                                            // we can diff these from: AssetBundle TypeTreeHash. we should load bundle.manifest and parse it use YAML. it's so difficult.
                                            // or we can get the ab file's change time. but this information is not recorded to zip
                                            // or we can get the crc of the entry. but it's private.
                                            // or we can get md5 of the entry. but need full read.
                                            // so we choose use length. In this condition, the ab file length's diff is almost a must.
                                            continue;
                                        }
                                    }
                                }
                            }
                            diffb.Add(bundle);
                        }
                    }

                    // create update zip
                    if (diffb.Count > 0)
                    {
                        try
                        {
                            var streama = PlatDependant.OpenWrite(diff);
                            if (streama != null)
                            {
                                lstToDispose.AddFirst(streama);
                                diffa = new ZipArchive(streama, ZipArchiveMode.Create);
                                if (diffa != null)
                                {
                                    lstToDispose.AddFirst(diffa);

                                    // each bundle
                                    foreach (var bundle in diffb)
                                    {
                                        try
                                        {
                                            var ename = abrootnew + bundle;
                                            var entryn = newa.GetEntry(ename);
                                            if (entryn != null)
                                            {
                                                var entryd = diffa.CreateEntry(ename, CompressionLevel.Optimal);
                                                if (entryd != null)
                                                {
                                                    using (var streamn = entryn.Open())
                                                    {
                                                        using (var streamd = entryd.Open())
                                                        {
                                                            streamn.CopyTo(streamd);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        catch { }
                                    }

                                    // mani / unity manifest / version.txt
                                    string[] rawcopyentries = new[] { mentry, umpathnew, "res/version.txt" };
                                    for (int i = 0; i < rawcopyentries.Length; ++i)
                                    {
                                        var ename = rawcopyentries[i];
                                        try
                                        {
                                            var entrys = newa.GetEntry(ename);
                                            if (entrys != null)
                                            {
                                                var entryd = diffa.CreateEntry(ename, CompressionLevel.Optimal);
                                                if (entryd != null)
                                                {
                                                    using (var streams = entrys.Open())
                                                    {
                                                        using (var streamd = entryd.Open())
                                                        {
                                                            streams.CopyTo(streamd);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        catch { }
                                    }
                                }
                            }
                        }
                        catch { }
                        return true;
                    }
                }
            }
            catch { }
            finally
            {
                foreach (var dis in lstToDispose)
                {
                    if (dis != null)
                    {
                        dis.Dispose();
                    }
                }
            }
            return false;
        }