Ejemplo n.º 1
0
        public void TestCompareMmo()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res\mmo");
            var path    = Path.Combine(resPath, "template39.json");
            var path2   = Path.Combine(resPath, "crash-temp.mmo");

            var mmo1     = PsbCompiler.LoadPsbFromJsonFile(path);
            var allpart1 = FindPart((PsbList)mmo1.Objects["objectChildren"], "body_parts");
            var mmo2     = new PSB(path2);
            var allpart2 = FindPart((PsbList)mmo2.Objects["objectChildren"], "body_parts");

            //var p1 = mmo1.Objects.FindByPath(
            //    "/objectChildren/[3]/children/[1]/layerChildren/[0]/children/[0]/frameList/[0]/content/coord");
            //var pp = ((IPsbChild) p1).Parent.Parent.Parent.Parent["label"];
            PsbDictionary FindPart(PsbList col, string label)
            {
                foreach (var c in col)
                {
                    if (c is PsbDictionary d)
                    {
                        if (d["label"] is PsbString s && s.Value == label)
                        {
                            return(d);
                        }
                    }
                }

                return(null);
            }

            //PsBuildTest.CompareValue(allpart1, allpart2);
            PsBuildTest.CompareValue(mmo1.Objects["metaformat"].Children("data"), mmo2.Objects["metaformat"].Children("data"));
        }
Ejemplo n.º 2
0
        public void TestFindByPath()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            var path = Path.Combine(resPath, "e-mote38_win-pure.psb.json");
            PSB psb  = PsbCompiler.LoadPsbFromJsonFile(path);

            var obj  = psb.Objects.FindByPath("/object/all_parts/motion/タイムライン構造/bounds");
            var type = obj.Type;

            var objs = psb.Objects.FindAllByPath("/object/*/motion/*");

            foreach (var psbValue in objs)
            {
                if (psbValue is PsbDictionary dic)
                {
                    var s = dic.GetName();
                    Console.WriteLine(s);
                }
                else
                {
                    Console.WriteLine($"Not a PsbObject: {psbValue}");
                }
            }
        }
Ejemplo n.º 3
0
        public void TestCompareDecompile()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            var pccPsb = new PSB(Path.Combine(resPath, "c01c.txt.scn"));
            //var pccPsb = new PSB(Path.Combine(resPath, "ca01_l_body_1.psz.psb-pure.psb"));
            //var pccPsb = new PSB(Path.Combine(resPath, "ca01.psb"));

            //var psbuildPsb = new PSB(Path.Combine(resPath, "ca01_l_body_1.psz.psb-pure.psb.json.psbuild.psb"));
            //var psbuildPsb = new PSB(Path.Combine(resPath, "dx_れいなh1a1.psb.json-pure.psb"));
            var psbuildPsb = PsbCompiler.LoadPsbFromJsonFile(Path.Combine(resPath, "c01c.txt.json"));

            //foreach (var s in psbuildPsb.Strings)
            //{
            //    var pccStr = pccPsb.Strings.Find(ss => ss.Value == s.Value);
            //    if (pccStr != null)
            //    {
            //        s.Index = pccStr.Index;
            //    }
            //    else
            //    {
            //        Console.WriteLine($"Can not find: {s}");
            //    }
            //}

            //psbuildPsb.UpdateIndexes();
            //File.WriteAllBytes(Path.Combine(resPath, "ca01_build.psb"), psbuildPsb.Build());

            CompareValue(pccPsb.Objects, psbuildPsb.Objects);
            //Console.WriteLine("============");
            //CompareValue(psbuildPsb.Objects, pccPsb.Objects);
        }
Ejemplo n.º 4
0
        public void TestCompileCommon()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var path    = Path.Combine(resPath, "emote396-a8l8.pure.json");
            var path2   = Path.Combine(resPath, "emote396-a8l8.pure.psb");
            var psb     = PsbCompiler.LoadPsbFromJsonFile(path);
            var psb2    = new PSB(path2);

            //File.WriteAllBytes("396.psb", psb.Build());
            PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 4, null, PsbSpec.win);
        }
Ejemplo n.º 5
0
        public void TestCompileEms()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            //var path = Path.Combine(resPath, "akira_guide-pure.psb.json");
            var path = Path.Combine(resPath, "emote_test2-pure.psb.json");
            var psb  = PsbCompiler.LoadPsbFromJsonFile(path);

            psb.Platform = PsbSpec.ems;
            psb.Merge();
            File.WriteAllBytes(path + ".build.psb", psb.Build());
            //PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 3, null, PsbSpec.ems);
        }
Ejemplo n.º 6
0
        public void TestPathTravel()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            var path = Path.Combine(resPath, "e-mote38_win-pure.psb.json");
            PSB psb  = PsbCompiler.LoadPsbFromJsonFile(path);

            var targetPath = "/object/all_parts/motion/タイムライン構造/bounds";
            var obj        = (PsbDictionary)psb.Objects.FindByPath(targetPath);
            var objPath    = obj.Path;

            Assert.AreEqual(targetPath, objPath);
        }
Ejemplo n.º 7
0
        public void TestConvertCommon2Krkr()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            var path = Path.Combine(resPath, "akira_guide-pure.psb.json");
            PSB psb  = PsbCompiler.LoadPsbFromJsonFile(path);

            Common2KrkrConverter converter = new Common2KrkrConverter();

            converter.Convert(psb);
            psb.Merge();
            File.WriteAllBytes("emote_test_front.psb", psb.Build());
            File.WriteAllText("emote_test_front.json", PsbDecompiler.Decompile(psb));
        }
Ejemplo n.º 8
0
 public void TestNaN()
 {
     var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
     //var path = Path.Combine(resPath, "dx_れいなh1a1.psb");
     //var psb = new PSB(path);
     var path = Path.Combine(resPath, "dx_れいなh1a1.psb.json");
     var psb  = PsbCompiler.LoadPsbFromJsonFile(path);
     var o    = psb.Objects.FindByPath(
         "/object/head_parts/motion/頭部変形基礎/layer/[0]/children/[3]/children/[0]/children/[0]/children/[0]/children/[0]/children/[0]/children/[0]/children/[0]/children/[0]/children/[1]/children/[0]/children/[0]/children/[0]/children/[0]/frameList/[0]/content/coord")
                as PsbCollection;
     var num    = o[0] as PsbNumber;
     var val    = num.IntValue;
     var valNaN = num.FloatValue;
 }
Ejemplo n.º 9
0
        public void TestPackMmo()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var path    = Path.Combine(resPath, "template39.json");
            var path2   = Path.Combine(resPath, "template39-krkr.json");
            var psb     = PsbCompiler.LoadPsbFromJsonFile(path);

            //var psb2 = PsbCompiler.LoadPsbFromJsonFile(path2);
            //psb.Objects["objectChildren"] = psb2.Objects["object"];
            //var collection = (PsbList)psb.Objects["objectChildren"];
            //collection.RemoveAt(0);
            psb.Objects["metaformat"] = PsbNull.Null;
            psb.Merge();
            psb.SaveAsMdfFile("temp.mmo");
        }
Ejemplo n.º 10
0
        public void TestFindPath()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            //var path = Path.Combine(resPath, "template39.json");
            var path = Path.Combine(resPath, "mmo", "NekoCrash.json");
            var mmo  = PsbCompiler.LoadPsbFromJsonFile(path);

            var children = (PsbList)mmo.Objects["objectChildren"];
            var source   = (PsbList)mmo.Objects["sourceChildren"];
            var obj      = (PsbDictionary)children.FindByMmoPath(
                "all_parts/全体構造/■全体レイアウト/move_UD/move_LR/□下半身配置_le/胴体回転中心/全身調整/□頭部調整_le/act_sp");
            var realPath = obj.Path;
            var mmoPath  = obj.GetMmoPath(); //"FreeMote/all_parts/全体構造/■全体レイアウト/move_UD/move_LR/□下半身配置_le/胴体回転中心/全身調整/□頭部調整_le/act_sp"
            //obj = source.FindByMmoPath("face_eye_mabuta_l");
        }
Ejemplo n.º 11
0
        public void TestConvertAndBuildMmo()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var path    = Path.Combine(resPath, "dx_e-moteショコラ小ex制服b.psb.json");
            var psb     = PsbCompiler.LoadPsbFromJsonFile(path);

            psb.SwitchSpec(PsbSpec.krkr);
            psb.Merge();
            //File.WriteAllBytes(Path.Combine(resPath, "neko-krkr.psb"), psb.Build());
            //return;
            MmoBuilder mmoBuilder = new MmoBuilder(true);
            var        psbMmo     = mmoBuilder.Build(psb);

            psbMmo.Merge();
            File.WriteAllBytes(Path.Combine(resPath, "mmo", "DxNekoCrash.mmo"), psbMmo.Build());
        }
Ejemplo n.º 12
0
        public void TestMmoGraft()
        {
            var        resPath    = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var        path       = Path.Combine(resPath, "template39.json");
            var        path2      = Path.Combine(resPath, "template39-krkr.json");
            var        mmo        = PsbCompiler.LoadPsbFromJsonFile(path);
            var        psb        = PsbCompiler.LoadPsbFromJsonFile(path2);
            MmoBuilder mmoBuilder = new MmoBuilder(true);
            var        psbMmo     = mmoBuilder.Build(psb);
            //mmo.Objects["objectChildren"] = psbMmo.Objects["objectChildren"];
            var data  = (PsbDictionary)mmo.Objects["metaformat"].Children("data");
            var data2 = (PsbDictionary)psbMmo.Objects["metaformat"].Children("data");

            data["bustControlDefinitionList"] = data2["bustControlDefinitionList"];
            mmo.Merge();
            mmo.SaveAsMdfFile(Path.Combine(resPath, "mmo", "temp.mmo"));
        }
Ejemplo n.º 13
0
        public void TestConvertKrkr2Win()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            //var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb");
            var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb.json");
            //var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb.json");
            //var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb");
            PSB psb = PsbCompiler.LoadPsbFromJsonFile(path);

            //PSB psb = new PSB(path);
            psb.SwitchSpec(PsbSpec.win);
            psb.Merge();
            File.WriteAllBytes("emote_krkr2win.psb", psb.Build());
            File.WriteAllText("emote_krkr2win.json", PsbDecompiler.Decompile(psb));
            RL.ConvertToImageFile(psb.Resources.First().Data, "tex-in-psb.png", 4096, 4096, PsbImageFormat.Png, PsbPixelFormat.WinRGBA8);
        }
Ejemplo n.º 14
0
        public void TestBuildMmo()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            var path    = Path.Combine(resPath, "e-mote3.0ショコラパジャマa中-krkr.json");
            //var path = Path.Combine(resPath, "template39-krkr.json");
            var        psb        = PsbCompiler.LoadPsbFromJsonFile(path);
            MmoBuilder mmoBuilder = new MmoBuilder(true);

            //Add custom menu paths
            mmoBuilder.CustomPartMenuPaths.Add("スカート", "胴体/スカート");
            mmoBuilder.CustomPartMenuPaths.Add("前髪_le1", "頭部/前髪1");
            mmoBuilder.CustomPartMenuPaths.Add("後髪_le4", "頭部/後髪4");
            mmoBuilder.CustomPartMenuPaths.Add("後髪_le5", "頭部/後髪5");

            var psbMmo = mmoBuilder.Build(psb);

            psbMmo.Merge();
            File.WriteAllBytes(Path.Combine(resPath, "mmo", "NekoCrash.mmo"), psbMmo.Build());
        }
Ejemplo n.º 15
0
        public void TestGraft()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            //var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb.json");
            var path    = Path.Combine(resPath, "e-mote38_KRKR-pure.psb.json");
            var path2   = Path.Combine(resPath, "e-mote38_win-pure.psb.json");
            PSB psbKrkr = PsbCompiler.LoadPsbFromJsonFile(path);
            PSB psbWin  = PsbCompiler.LoadPsbFromJsonFile(path2);

            psbWin.SwitchSpec(PsbSpec.krkr);
            //var metadata = (PsbDictionary)psbWin.Objects["metadata"];
            //metadata["attrcomp"] = psbKrkr.Objects["metadata"].Children("attrcomp");
            psbWin.Merge();

            ////Graft
            var resKrkr  = psbKrkr.CollectResources(false);
            var resWin   = psbWin.CollectResources(false);
            var headWin  = resWin.FirstOrDefault(r => r.Height == 186 && r.Width == 122);
            var headKrkr = resKrkr.FirstOrDefault(r => r.Height == 186 && r.Width == 122);

            if (headWin != null && headKrkr != null)
            {
                headWin.Resource.Data = headKrkr.Resource.Data;
            }

            //foreach (var resourceMetadata in resWin)
            //{
            //    var sameRes = resKrkr.FirstOrDefault(r => r.Height == resourceMetadata.Height && r.Width == resourceMetadata.Width);
            //    if (sameRes != null)
            //    {
            //        Console.WriteLine($"{sameRes} {sameRes.Width}x{sameRes.Height} found.");
            //        resourceMetadata.Resource.Data = sameRes.Resource.Data;
            //    }
            //}
            psbWin.Merge();
            File.WriteAllBytes("emote_win2krkr.psb", psbWin.Build());
            //File.WriteAllText("emote_krkr2win.json", PsbDecompiler.Decompile(psb2));
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Pack Archive PSB
        /// </summary>
        /// <param name="jsonPath">json path</param>
        /// <param name="key">crypt key</param>
        /// <param name="intersect">Only pack files which existed in info.psb.m</param>
        /// <param name="preferPacked">Prefer using PSB files rather than json files in source folder</param>
        /// <param name="enableParallel">parallel process</param>
        /// <param name="keyLen">key length</param>
        /// <param name="keepRaw">Do not try to compile json or pack MDF</param>
        public static void PackArchive(string jsonPath, string key, bool intersect, bool preferPacked, bool enableParallel = true,
                                       int keyLen = 131, bool keepRaw = false)
        {
            if (!File.Exists(jsonPath))
            {
                return;
            }
            PSB infoPsb = PsbCompiler.LoadPsbFromJsonFile(jsonPath);

            if (infoPsb.Type != PsbType.ArchiveInfo)
            {
                Console.WriteLine("Json is not an ArchiveInfo PSB.");
                return;
            }

            var resx = PsbResourceJson.LoadByPsbJsonPath(jsonPath);

            if (!resx.Context.ContainsKey(Context_ArchiveSource) ||
                resx.Context[Context_ArchiveSource] == null)
            {
                Console.WriteLine("ArchiveSource must be specified in resx.json Context.");
                return;
            }

            if (keyLen > 0)
            {
                resx.Context[Context_MdfKeyLength] = keyLen;
            }

            string infoKey = null;

            if (resx.Context[Context_MdfKey] is string mdfKey)
            {
                infoKey = mdfKey;
            }

            List <string> sourceDirs = null;

            if (resx.Context[Context_ArchiveSource] is string path)
            {
                sourceDirs = new List <string> {
                    path
                };
            }
            else if (resx.Context[Context_ArchiveSource] is IList paths)
            {
                sourceDirs = new List <string>(paths.Count);
                sourceDirs.AddRange(from object p in paths select p.ToString());
            }
            else
            {
                Console.WriteLine("ArchiveSource incorrect.");
                return;
            }

            var           baseDir = Path.GetDirectoryName(jsonPath);
            var           files   = new Dictionary <string, (string Path, ProcessMethod Method)>();
            var           suffix  = ArchiveInfoGetSuffix(infoPsb);
            List <string> filter  = null;

            if (intersect) //only collect files appeared in json
            {
                filter = ArchiveInfoCollectFiles(infoPsb, suffix).ToList();
            }

            void CollectFiles(string targetDir)
            {
                if (!Directory.Exists(targetDir))
                {
                    return;
                }

                foreach (var f in Directory.EnumerateFiles(targetDir))
                {
                    if (f.EndsWith(".resx.json", true, CultureInfo.InvariantCulture))
                    {
                        continue;
                    }
                    else if (f.EndsWith(".json", true, CultureInfo.InvariantCulture)) //json source, need compile
                    {
                        var name = Path.GetFileNameWithoutExtension(f);
                        if (preferPacked && files.ContainsKey(name) &&
                            files[name].Method != ProcessMethod.Compile) //it's always right no matter set or replace
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name)) //this file is not appeared in json
                            {
                                //ignore
                            }
                            else
                            {
                                files[name] = (f, keepRaw? ProcessMethod.None: ProcessMethod.Compile);
                            }
                        }
                    }
                    else
                    {
                        var name = Path.GetFileName(f);
                        if (!preferPacked && files.ContainsKey(name) &&
                            files[name].Method == ProcessMethod.Compile)
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name))
                            {
                                //ignore
                            }
                            else
                            {
                                using var fs = File.OpenRead(f);
                                if (!MdfFile.IsSignatureMdf(fs) && name.DefaultShellType() == "MDF")
                                {
                                    files[name] = (f, keepRaw? ProcessMethod.None: ProcessMethod.EncodeMdf);
                                }
                                else
                                {
                                    files[name] = (f, ProcessMethod.None);
                                }
                            }
                        }
                    }
                }
            }

            //Collect files
            Console.WriteLine("Collecting files ...");
            foreach (var sourceDir in sourceDirs)
            {
                CollectFiles(Path.IsPathRooted(sourceDir) ? sourceDir : Path.Combine(baseDir, sourceDir));
            }

            Console.WriteLine($"Packing {files.Count} files ...");
            var bodyBinFileName = Path.GetFileName(jsonPath);
            var packageName     = Path.GetFileNameWithoutExtension(bodyBinFileName);

            var coreName = ArchiveInfoGetPackageName(packageName);

            bodyBinFileName = string.IsNullOrEmpty(coreName) ? packageName + "_body.bin" : coreName + "_body.bin";

            //using var mmFile =
            //    MemoryMappedFile.CreateFromFile(bodyBinFileName, FileMode.Create, coreName, );
            using var bodyFs = File.OpenWrite(bodyBinFileName);
            var fileInfoDic = new PsbDictionary(files.Count);
            var fmContext   = FreeMount.CreateContext(resx.Context);

            //byte[] bodyBin = null;
            if (enableParallel)
            {
                var contents = new ConcurrentBag <(string Name, Stream Content)>();
                Parallel.ForEach(files, (kv) =>
                {
                    var fileNameWithoutSuffix = ArchiveInfoGetFileNameRemoveSuffix(kv.Key, suffix);

                    if (kv.Value.Method == ProcessMethod.None)
                    {
                        contents.Add((fileNameWithoutSuffix, File.OpenRead(kv.Value.Path)));
                        return;
                    }

                    var mdfContext = new Dictionary <string, object>(resx.Context);
                    var context    = FreeMount.CreateContext(mdfContext);
                    if (!string.IsNullOrEmpty(key))
                    {
                        mdfContext[Context_MdfKey] = key + kv.Key;
                    }
                    else if (resx.Context[Context_MdfMtKey] is string mtKey)
                    {
                        mdfContext[Context_MdfKey] = mtKey + kv.Key;
                    }
                    else
                    {
                        mdfContext.Remove(Context_MdfKey);
                    }

                    mdfContext.Remove(Context_ArchiveSource);

                    if (kv.Value.Method == ProcessMethod.EncodeMdf)
                    {
                        using var mmFs = MemoryMappedFile.CreateFromFile(kv.Value.Path, FileMode.Open);

                        //using var fs = File.OpenRead(kv.Value.Path);
                        contents.Add((fileNameWithoutSuffix, context.PackToShell(mmFs.CreateViewStream(), "MDF"))); //disposed later
                    }
                    else
                    {
                        var content   = PsbCompiler.LoadPsbAndContextFromJsonFile(kv.Value.Path);
                        var stream    = content.Psb.ToStream();
                        var shellType = kv.Key.DefaultShellType(); //MARK: use shellType in filename, or use suffix in info?
                        if (!string.IsNullOrEmpty(shellType))
                        {
                            stream = context.PackToShell(stream, shellType); //disposed later
                        }
                        contents.Add((fileNameWithoutSuffix, stream));
                    }
                });
Ejemplo n.º 17
0
        /// <summary>
        /// Pack Archive PSB
        /// </summary>
        /// <param name="jsonPath">json path</param>
        /// <param name="key">crypt key</param>
        /// <param name="intersect">Only pack files which existed in info.psb.m</param>
        /// <param name="preferPacked">Prefer using PSB files rather than json files in source folder</param>
        /// <param name="enableParallel">parallel process</param>
        /// <param name="keyLen">key length</param>
        public static void PackArchive(string jsonPath, string key, bool intersect, bool preferPacked, bool enableParallel = true,
                                       int keyLen = 131)
        {
            if (!File.Exists(jsonPath))
            {
                return;
            }
            PSB infoPsb = PsbCompiler.LoadPsbFromJsonFile(jsonPath);

            if (infoPsb.Type != PsbType.ArchiveInfo)
            {
                Console.WriteLine("Json is not an ArchiveInfo PSB.");
                return;
            }

            var resx = PsbResourceJson.LoadByPsbJsonPath(jsonPath);

            if (!resx.Context.ContainsKey(Context_ArchiveSource) ||
                resx.Context[Context_ArchiveSource] == null)
            {
                Console.WriteLine("ArchiveSource must be specified in resx.json Context.");
                return;
            }

            if (keyLen > 0)
            {
                resx.Context[Context_MdfKeyLength] = keyLen;
            }

            string infoKey = null;

            if (resx.Context[Context_MdfKey] is string mdfKey)
            {
                infoKey = mdfKey;
            }

            List <string> sourceDirs = null;

            if (resx.Context[Context_ArchiveSource] is string path)
            {
                sourceDirs = new List <string> {
                    path
                };
            }
            else if (resx.Context[Context_ArchiveSource] is IList paths)
            {
                sourceDirs = new List <string>(paths.Count);
                sourceDirs.AddRange(from object p in paths select p.ToString());
            }
            else
            {
                Console.WriteLine("ArchiveSource incorrect.");
                return;
            }

            var           baseDir = Path.GetDirectoryName(jsonPath);
            var           files   = new Dictionary <string, (string Path, ProcessMethod Method)>();
            var           suffix  = ArchiveInfoPsbGetSuffix(infoPsb);
            List <string> filter  = null;

            if (intersect)
            {
                filter = ArchiveInfoPsbCollectFiles(infoPsb, suffix);
            }

            void CollectFiles(string targetDir)
            {
                if (!Directory.Exists(targetDir))
                {
                    return;
                }

                foreach (var f in Directory.EnumerateFiles(targetDir))
                {
                    if (f.EndsWith(".resx.json", true, CultureInfo.InvariantCulture))
                    {
                        continue;
                    }
                    else if (f.EndsWith(".json", true, CultureInfo.InvariantCulture))
                    {
                        var name = Path.GetFileNameWithoutExtension(f);
                        if (preferPacked && files.ContainsKey(name) &&
                            files[name].Method != ProcessMethod.Compile)
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name))
                            {
                                //ignore
                            }
                            else
                            {
                                files[name] = (f, ProcessMethod.Compile);
                            }
                        }
                    }
                    else
                    {
                        var name = Path.GetFileName(f);
                        if (!preferPacked && files.ContainsKey(name) &&
                            files[name].Method == ProcessMethod.Compile)
                        {
                            //ignore
                        }
                        else
                        {
                            if (intersect && filter != null && !filter.Contains(name))
                            {
                                //ignore
                            }
                            else
                            {
                                using var fs = File.OpenRead(f);
                                if (!MdfFile.IsSignatureMdf(fs) && name.DefaultShellType() == "MDF")
                                {
                                    files[name] = (f, ProcessMethod.EncodeMdf);
                                }
                                else
                                {
                                    files[name] = (f, ProcessMethod.None);
                                }
                            }
                        }
                    }
                }
            }

            //Collect files
            foreach (var sourceDir in sourceDirs)
            {
                CollectFiles(Path.IsPathRooted(sourceDir) ? sourceDir : Path.Combine(baseDir, sourceDir));
            }

            var fileName    = Path.GetFileName(jsonPath);
            var packageName = Path.GetFileNameWithoutExtension(fileName);

            var coreName = PsbExtension.ArchiveInfoGetPackageName(packageName);

            fileName = string.IsNullOrEmpty(coreName) ? packageName + "_body.bin" : coreName + "_body.bin";

            var fileInfoDic = new PsbDictionary(files.Count);
            var fmContext   = FreeMount.CreateContext(resx.Context);

            byte[] bodyBin = null;
            if (enableParallel)
            {
                var contents = new ConcurrentBag <(string Name, Stream Content)>();
                Parallel.ForEach(files, (kv) =>
                {
                    var fileNameWithoutSuffix = ArchiveInfoPsbGetFileName(kv.Key, suffix);
                    if (kv.Value.Method == ProcessMethod.None)
                    {
                        contents.Add((fileNameWithoutSuffix, File.OpenRead(kv.Value.Path)));
                        return;
                    }

                    var mdfContext = new Dictionary <string, object>(resx.Context);
                    var context    = FreeMount.CreateContext(mdfContext);
                    if (!string.IsNullOrEmpty(key))
                    {
                        mdfContext[Context_MdfKey] = key + fileNameWithoutSuffix + suffix;
                    }
                    else if (resx.Context[Context_MdfMtKey] is string mtKey)
                    {
                        mdfContext[Context_MdfKey] =
                            mtKey + fileNameWithoutSuffix + suffix;
                    }
                    else
                    {
                        mdfContext.Remove(Context_MdfKey);
                    }

                    mdfContext.Remove(Context_ArchiveSource);

                    if (kv.Value.Method == ProcessMethod.EncodeMdf)
                    {
                        contents.Add((fileNameWithoutSuffix, context.PackToShell(
                                          File.OpenRead(kv.Value.Path), "MDF")));
                    }
                    else
                    {
                        var content = PsbCompiler.LoadPsbAndContextFromJsonFile(kv.Value.Path);

                        var outputMdf = context.PackToShell(content.Psb.ToStream(), "MDF");
                        contents.Add((fileNameWithoutSuffix, outputMdf));
                    }
                });