Пример #1
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);
        }
Пример #2
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"));
        }
Пример #3
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}");
                }
            }
        }
Пример #4
0
        private static void Compile(string s, ushort version, uint?key, PsbSpec?spec, bool canRename,
                                    bool canPackShell)
        {
            if (!File.Exists(s))
            {
                //此処にいて何処にもいない キミの面影はいつも朧 : https://soundcloud.com/yuhyuhyuhxibbd2/parallel-utau
                return;
            }

            var name = Path.GetFileNameWithoutExtension(s);
            var ext  = Path.GetExtension(s);

            Console.WriteLine($"Compiling {name} ...");
            try
            {
                //var filename = name + (_key == null ? _noRename ? ".psb" : "-pure.psb" : "-impure.psb");
                var filename = name + ".psb";
                PsbCompiler.CompileToFile(s, filename, null, version, key, spec, canRename,
                                          canPackShell);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Compile {name} failed.\r\n{e}");
            }

            Console.WriteLine($"Compile {name} succeed.");
        }
Пример #5
0
        public void TestCompileMenuPsb()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");

            var path = Path.Combine(resPath, "title.psb.json");

            PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 2);
        }
Пример #6
0
        public void TestCompileWin()
        {
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            //var path = Path.Combine(resPath, "D愛子a_春服-pure.psb.json");
            var path = Path.Combine(resPath, "dx_れいなh1a1.psb.json");

            PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 4, null, PsbSpec.win);
        }
Пример #7
0
        public void TestCompileKrkr()
        {
            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");

            PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 4, null, PsbSpec.win);
        }
Пример #8
0
        public void TestInplaceReplace()
        {
            FreeMount.Init();
            var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res");
            //var path = Path.Combine(resPath, "dx_ふかみ_駅員服.psb");
            var path     = Path.Combine(resPath, "dx_ふかみ_駅員服.lz4.psb");
            var jsonPath = Path.Combine(resPath, "dx_ふかみ_駅員服.json");

            PsbCompiler.InplaceReplaceToFile(path, jsonPath);
        }
Пример #9
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);
        }
Пример #10
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);
        }
Пример #11
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);
        }
Пример #12
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));
        }
Пример #13
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;
 }
Пример #14
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");
        }
Пример #15
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");
        }
Пример #16
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());
        }
Пример #17
0
        private static void Compile(string s)
        {
            var name = Path.GetFileNameWithoutExtension(s);
            var ext  = Path.GetExtension(s);

            Console.WriteLine($"Compiling {name} ...");
            try
            {
                PsbCompiler.CompileToFile(s, s + (_key == null ? "-pure.psb" : ".psb"), null, _version, _key, _platform);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Compile {name} failed.\r\n{e}");
            }
            Console.WriteLine($"Compile {name} succeed.");
        }
Пример #18
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);
        }
Пример #19
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"));
        }
Пример #20
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());
        }
Пример #21
0
        // 적용 버튼
        private void button2_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFile = new OpenFileDialog())
            {
                openFile.Title       = "적용할 SCN 파일을 선택해주세요. (다중 선택 가능)";
                openFile.DefaultExt  = "scn";
                openFile.Filter      = "SCN 파일 (*.scn)|*.scn;";
                openFile.Multiselect = true;

                if (openFile.ShowDialog() == DialogResult.OK)
                {
                    progressBar1.Value   = 0;
                    progressBar1.Maximum = openFile.FileNames.Length;
                    label2.Text          = $"0/{progressBar1.Maximum}";

                    foreach (var file in openFile.FileNames)
                    {
                        string json = file.Substring(0, file.Length - 3) + "json";
                        Apply(json);

                        progressBar1.PerformStep();
                        label2.Text = $"{progressBar1.Value}/{progressBar1.Maximum}";
                    }

                    progressBar1.Value = 0;

                    foreach (var file in openFile.FileNames)
                    {
                        string json = file.Substring(0, file.Length - 3) + "json";

                        PsbCompiler.CompileToFile(json, json, null, null, null, null);
                        var purescn = file.Substring(0, file.Length - 3) + "pure.scn";

                        File.Delete(file);
                        File.Move(purescn, file);

                        progressBar1.PerformStep();
                        label2.Text = $"{progressBar1.Value}/{progressBar1.Maximum}";
                    }
                }
            }
        }
Пример #22
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));
        }
Пример #23
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));
                    }
                });
Пример #24
0
        //private static PsbPixelFormat _pixelFormat = PsbPixelFormat.None;

        static void Main(string[] args)
        {
            Console.WriteLine("FreeMote PSB Compiler");
            Console.WriteLine("by Ulysses, [email protected]");

            FreeMount.Init();
            Console.WriteLine($"{FreeMount.PluginsCount} Plugins Loaded.");

            InMemoryLoading = true;
            Console.WriteLine();

            var app = new CommandLineApplication();

            app.OptionsComparison = StringComparison.OrdinalIgnoreCase;

            //help
            app.HelpOption();
            app.ExtendedHelpText = PrintHelp();

            //options
            var optVer = app.Option <ushort>("-v|--ver <VER>", "Set PSB version [2,4]. Default=3",
                                             CommandOptionType.SingleValue);
            var optKey  = app.Option <uint>("-k|--key <KEY>", "Set PSB key (uint, dec)", CommandOptionType.SingleValue);
            var optSpec = app.Option <PsbSpec>("-p|--spec <SPEC>", "Set PSB platform (krkr/common/win/ems)",
                                               CommandOptionType.SingleValue);
            var optNoRename = app.Option("-no-rename",
                                         "Prevent output file renaming, may overwrite your original PSB files", CommandOptionType.NoValue);
            var optNoShell = app.Option("-no-shell", "Prevent shell packing (compression)", CommandOptionType.NoValue);
            var optDouble  = app.Option("-double|--json-double", "(Json) Use double numbers only (no float)",
                                        CommandOptionType.NoValue, true);
            //var optOutputPath =
            //  app.Option<string>("-o|--output", "(TODO:)Set output directory or file name.", CommandOptionType.SingleValue);
            //TODO: If set dir, ok; if set filename, only works for the first

            //args
            var argPath =
                app.Argument("Files", "File paths", multipleValues: true);

            //command: link
            app.Command("link", linkCmd =>
            {
                //help
                linkCmd.Description = "Link textures into an external texture PSB";
                linkCmd.HelpOption();
                linkCmd.ExtendedHelpText = @"
Example:
  PsBuild link -o Order sample.psb tex000.png tex001.bmp 
";
                //options
                var optOrder = linkCmd.Option <PsbLinkOrderBy>("-o|--order <ORDER>",
                                                               "Set texture link order (Name/Order/Convention). Default=Name",
                                                               CommandOptionType.SingleValue);
                //args
                var argPsbPath  = linkCmd.Argument("PSB", "PSB Path").IsRequired().Accepts(v => v.ExistingFile());
                var argTexPaths = linkCmd.Argument("Textures", "Texture Paths", true).IsRequired();

                linkCmd.OnExecute(() =>
                {
                    var order    = optOrder.HasValue() ? optOrder.ParsedValue : PsbLinkOrderBy.Name;
                    var psbPath  = argPsbPath.Value;
                    var texPaths = argTexPaths.Values;
                    Link(psbPath, texPaths, order);
                });
            });

            //command: port
            app.Command("port", portCmd =>
            {
                //help
                portCmd.Description = "Re-compile a PSB to another platform";
                portCmd.HelpOption();
                portCmd.ExtendedHelpText = @"
Example:
  PsBuild port -p win sample.psb 
";
                //options
                var optPortSpec = portCmd.Option <PsbSpec>("-p|--spec <SPEC>",
                                                           "Target PSB platform (krkr/common/win/ems)",
                                                           CommandOptionType.SingleValue).IsRequired();
                //args
                var argPsbPath = portCmd.Argument("PSB", "PSB Path", multipleValues: true).IsRequired();

                portCmd.OnExecute(() =>
                {
                    var portSpec = optPortSpec.ParsedValue;
                    var psbPaths = argPsbPath.Values;
                    foreach (var s in psbPaths)
                    {
                        if (File.Exists(s))
                        {
                            Port(s, portSpec);
                        }
                    }
                });
            });

            //info-psb
            app.Command("info-psb", archiveCmd =>
            {
                //help
                archiveCmd.Description = "Pack files to info.psb.m & body.bin (FreeMote.Plugins required)";
                archiveCmd.HelpOption();
                archiveCmd.ExtendedHelpText = @"
Example:
  PsBuild info-psb sample_info.psb.m.json (Key specified in resx.json)
  PsBuild info-psb -k 1234567890ab -l 131 sample_info.psb.m.json (Must keep every filename correct)
  Hint: Always keep file names correct. A file name in source folder must match a name kept in .m.json
  If there are both `.m` and `.m.json` in the source folder, `.json` will be used (unless using `--packed`).
  If you don't have enough RAM to keep the whole output, use `-1by1` and wait patiently.
";
                //options
                //var optMdfSeed = archiveCmd.Option("-s|--seed <SEED>",
                //    "Set complete seed (Key+FileName)",
                //    CommandOptionType.SingleValue);
                var optIntersect = archiveCmd.Option("-i|--intersect",
                                                     "Only pack files which existed in info.psb.m",
                                                     CommandOptionType.NoValue);
                var optPacked = archiveCmd.Option("-p|--packed",
                                                  "Prefer using PSB files rather than json files in source folder",
                                                  CommandOptionType.NoValue);
                var optMdfKey = archiveCmd.Option("-k|--key <KEY>",
                                                  "Set key (get file name from input path)",
                                                  CommandOptionType.SingleValue);
                var optMdfKeyLen = archiveCmd.Option <int>("-l|--length <LEN>",
                                                           "Set key length. Default=131",
                                                           CommandOptionType.SingleValue);
                var optInfoOom = archiveCmd.Option("-1by1|--enumerate",
                                                   "Disable parallel processing (can be slow but save a lot memory)", CommandOptionType.NoValue);
                var optInfoRaw = archiveCmd.Option("-raw|--raw",
                                                   "Keep all sources raw (don't compile jsons or pack MDF shell)", CommandOptionType.NoValue);

                //args
                var argPsbPaths = archiveCmd.Argument("PSB", "Archive Info PSB .json paths", true);

                archiveCmd.OnExecute(() =>
                {
                    bool intersect      = optIntersect.HasValue();
                    bool preferPacked   = optPacked.HasValue();
                    bool enableParallel = FastMode;
                    bool keepRaw        = false;
                    if (optInfoOom.HasValue())
                    {
                        enableParallel = false;
                    }

                    if (optInfoRaw.HasValue())
                    {
                        keepRaw = true;
                    }

                    string key = optMdfKey.HasValue() ? optMdfKey.Value() : null;
                    //string seed = optMdfSeed.HasValue() ? optMdfSeed.Value() : null;

                    int keyLen = optMdfKeyLen.HasValue() ? optMdfKeyLen.ParsedValue : 131;

                    Stopwatch sw = Stopwatch.StartNew();
                    foreach (var s in argPsbPaths.Values)
                    {
                        PackArchive(s, key, intersect, preferPacked, enableParallel, keyLen, keepRaw);
                    }
                    sw.Stop();
                    Console.WriteLine($"Process time: {sw.Elapsed:g}");
                });
            });

            //command: replace
            app.Command("replace", replaceCmd =>
            {
                //help
                replaceCmd.Description = "In-place Replace the images in PSB";
                replaceCmd.HelpOption();
                replaceCmd.ExtendedHelpText = @"
Example:
  PsBuild replace sample.psb sample.json
  Hint: Only works with textures not compressed (RGBA8, RGBA4444) pure PSBs.
";
                var argPsbPath  = replaceCmd.Argument("PSB", "PSB path", false);
                var argJsonPath = replaceCmd.Argument("Json", "PSB Json path", false);

                replaceCmd.OnExecute(() =>
                {
                    if (!File.Exists(argPsbPath.Value) || !File.Exists(argJsonPath.Value))
                    {
                        Console.WriteLine("File not exists.");
                        return;
                    }

                    var output = PsbCompiler.InplaceReplaceToFile(argPsbPath.Value, argJsonPath.Value);
                    Console.WriteLine($"In-place Replace Output: {output}");
                });
            });

            app.OnExecute(() =>
            {
                if (optDouble.HasValue())
                {
                    JsonUseDoubleOnly = true;
                }

                ushort?ver    = optVer.HasValue() ? optVer.ParsedValue : (ushort?)null;
                uint?key      = optKey.HasValue() ? optKey.ParsedValue : (uint?)null;
                PsbSpec?spec  = optSpec.HasValue() ? optSpec.ParsedValue : (PsbSpec?)null;
                var canRename = !optNoRename.HasValue();
                var canPack   = !optNoShell.HasValue();

                foreach (var file in argPath.Values)
                {
                    Compile(file, ver, key, spec, canRename, canPack);
                }
            });

            if (args.Length == 0)
            {
                app.ShowHelp();
                return;
            }

            app.Execute(args);

            Console.WriteLine("Done.");
        }
Пример #25
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));
                    }
                });