static void Main(string[] args) { Console.WriteLine("FreeMote MMO Decompiler (Preview)"); Console.WriteLine("by Ulysses, [email protected]"); FreeMount.Init(); Console.WriteLine(); Console.WriteLine("This is a preview version. If it crashes, send the PSB to me."); Console.WriteLine("All output files from this tool should follow [CC BY-NC-SA 4.0] license. Agree this license by pressing Enter:"); Console.ReadLine(); if (args.Length < 1 || !File.Exists(args[0])) { return; } PSB psb = null; try { psb = new PSB(args[0]); } catch (Exception e) { Console.WriteLine("Input PSB is invalid."); } if (psb != null) { psb.FixMotionMetadata(); //Fix for partial exported PSB if (psb.Platform != PsbSpec.krkr) { if (psb.Platform == PsbSpec.common || psb.Platform == PsbSpec.win) { psb.SwitchSpec(PsbSpec.krkr); psb.Merge(); } else { Console.WriteLine( $"EmtMake do not support {psb.Platform} PSB. Please use pure krkr PSB."); goto END; } } #if !DEBUG try #endif { MmoBuilder builder = new MmoBuilder(); var output = builder.Build(psb); output.Merge(); File.WriteAllBytes(Path.ChangeExtension(args[0], ".FreeMote.mmo"), output.Build()); } #if !DEBUG catch (Exception e) { Console.WriteLine(e); } #endif } END: Console.WriteLine("Done."); Console.ReadLine(); }
static void Main(string[] args) { Console.WriteLine("FreeMote PSB Converter"); Console.WriteLine("by Ulysses, [email protected]"); FreeMount.Init(); Console.WriteLine($"{FreeMount.PluginsCount} Plugins Loaded."); Console.WriteLine(); var app = new CommandLineApplication(); app.OptionsComparison = StringComparison.OrdinalIgnoreCase; //help app.HelpOption(); app.ExtendedHelpText = PrintHelp(); //options var optKey = app.Option <uint>("-k|--key <KEY>", "PSB key (uint, dec)", CommandOptionType.SingleValue); var optNewKey = app.Option <uint>("-nk|--new-key <KEY>", "New PSB key for transfer (uint, dec)", CommandOptionType.SingleValue); //args var argPath = app.Argument("Files", "File paths", multipleValues: true); //command: pixel app.Command("pixel", pixelCmd => { //help pixelCmd.Description = "Convert pixel colors of extracted images (RGBA BMP/PNG)"; pixelCmd.HelpOption(); pixelCmd.ExtendedHelpText = @" Example: EmtConvert pixel -m Switch02 sample.png "; //options var optMethod = pixelCmd.Option <PsbImageConvertMethod>("-m|--method <METHOD>", "Set convert method", CommandOptionType.SingleValue); //args var argPaths = pixelCmd.Argument("Image", "Image Paths", true); pixelCmd.OnExecute(() => { if (!optMethod.HasValue()) { Console.WriteLine("Convert Method is not specified!"); return; } foreach (var path in argPaths.Values) { if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { continue; } int width = 0; int height = 0; PixelFormat pixelFormat = PixelFormat.Format32bppArgb; try { var img = Image.FromFile(path); width = img.Width; height = img.Height; pixelFormat = img.PixelFormat; } catch (Exception e) { Console.WriteLine(e); continue; } var bts = RL.GetPixelBytesFromImageFile(path); switch (optMethod.ParsedValue) { case PsbImageConvertMethod.Switch02: RL.Switch_0_2(ref bts); break; case PsbImageConvertMethod.ROR: RL.Argb2Rgba(ref bts); break; case PsbImageConvertMethod.ROL: RL.Argb2Rgba(ref bts, true); break; case PsbImageConvertMethod.LeARGB_4To8: bts = RL.Argb428(bts); break; case PsbImageConvertMethod.LeARGB_TO_L8Grayscale: bts = RL.Argb2L8(bts); bts = RL.ReadL8(bts, height, width); break; case PsbImageConvertMethod.Untile: bts = PostProcessing.UntileTexture(bts, width, height, pixelFormat); break; case PsbImageConvertMethod.Unswizzle: bts = PostProcessing.UnswizzleTexture(bts, width, height, pixelFormat); break; case PsbImageConvertMethod.Tile: bts = PostProcessing.TileTexture(bts, width, height, pixelFormat); break; case PsbImageConvertMethod.Swizzle: bts = PostProcessing.SwizzleTexture(bts, width, height, pixelFormat); break; default: continue; } RL.ConvertToImageFile(bts, Path.ChangeExtension(path, ".converted.png"), height, width, PsbImageFormat.png); } }); }); //command: pack app.Command("pack", packCmd => { //help packCmd.Description = "Pack/Unpack PSBs to/from shell (FreeMote.Plugins required)"; packCmd.HelpOption(); packCmd.ExtendedHelpText = @" Example: EmtConvert pack -s LZ4 sample.psb "; //options var optType = packCmd.Option("-s|--shell <SHELL>", "Set shell type. No need to specify if unpack", CommandOptionType.SingleValue); //args var argPsbPaths = packCmd.Argument("PSB", "MDF/PSB Paths", true); packCmd.OnExecute(() => { string type = optType.HasValue() ? optType.Value() : null; foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { ShellConvert(s, type); } } }); }); //command: print app.Command("print", printCmd => { //help printCmd.Description = "Print an EMT PSB (for its initial state, don't expect it working)"; printCmd.HelpOption(); printCmd.ExtendedHelpText = @" Example: EmtConvert print -w 4096 -h 4096 sample.psb "; //options var optWidth = printCmd.Option <int>("-w|--width <INT>", "Set width. Default=-1 (auto)", CommandOptionType.SingleValue); var optHeight = printCmd.Option <int>("-h|--height <INT>", "Set height. Default=-1 (auto)", CommandOptionType.SingleValue); //args var argPsbPaths = printCmd.Argument("PSB", "MDF/PSB Paths", true); printCmd.OnExecute(() => { int width = optWidth.HasValue() ? optWidth.ParsedValue : -1; int height = optHeight.HasValue() ? optHeight.ParsedValue : -1; foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { Draw(s, width, height); } } }); }); //command: fix app.Command("fix", fixCmd => { //help fixCmd.Description = "Some mysterious fixes for PSB"; fixCmd.HelpOption(); fixCmd.ExtendedHelpText = @" Example: EmtConvert fix -m MetadataBase sample.psb "; //options var optMethod = fixCmd.Option <PsbFixMethod>("-m|--method <METHOD>", "Set fix method.", CommandOptionType.SingleValue); //args var argPsbPaths = fixCmd.Argument("PSB", "PSB Paths", true); fixCmd.OnExecute(() => { if (!optMethod.HasValue()) { Console.WriteLine("Fix Method is not specified!"); return; } var method = optMethod.ParsedValue; foreach (var s in argPsbPaths.Values) { if (!File.Exists(s)) { continue; } switch (method) { case PsbFixMethod.MetadataBase: { Console.Write($"Using {method} to fix {s} ..."); PSB psb = new PSB(s); if (psb.FixMotionMetadata()) { psb.BuildToFile(Path.ChangeExtension(s, ".fixed.psb")); Console.WriteLine("Fixed!"); } else { Console.WriteLine("not fixed."); } } break; default: Console.WriteLine($"Not implemented method: {method}"); break; } } }); }); //mdf app.Command("mdf", mdfCmd => { //help mdfCmd.Description = "Pack/Unpack MT19937 encrypted MDF (FreeMote.Plugins required)"; mdfCmd.HelpOption(); mdfCmd.ExtendedHelpText = @" Example: EmtConvert mdf -k 1234567890ab -l 131 sample.psb EmtConvert mdf -s 1234567890absample.psb -l 131 sample.psb Hint: To pack a pure MDF, use `EmtConvert pack -s MDF <MDF file>` "; //options //var optMdfPack = mdfCmd.Option("-p|--pack", // "Pack (Encrypt) a PSB to MT19937 MDF", // CommandOptionType.NoValue); var optMdfSeed = mdfCmd.Option("-s|--seed <SEED>", "Set complete seed (Key+FileName)", CommandOptionType.SingleValue); var optMdfKey = mdfCmd.Option("-k|--key <KEY>", "Set key (Infer file name from path)", CommandOptionType.SingleValue); var optMdfKeyLen = mdfCmd.Option <uint>("-l|--length <LEN>", "Set key length (not required if decrypt all bytes). Usually use 131.", CommandOptionType.SingleValue); //args var argPsbPaths = mdfCmd.Argument("PSB", "PSB Paths", true); mdfCmd.OnExecute(() => { string key = optMdfKey.HasValue() ? optMdfKey.Value() : null; string seed = optMdfSeed.HasValue() ? optMdfSeed.Value() : null; if (string.IsNullOrEmpty(key) && string.IsNullOrEmpty(seed)) { //throw new ArgumentNullException(nameof(key), "No key or seed specified."); Console.WriteLine("No key or seed specified. Packing to pure MDF."); foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { ShellConvert(s, "MDF"); } } return; } Dictionary <string, object> context = new Dictionary <string, object>(); uint?keyLen = optMdfKeyLen.HasValue() ? optMdfKeyLen.ParsedValue : (uint?)null; if (keyLen.HasValue) { context[Context_MdfKeyLength] = keyLen; } foreach (var s in argPsbPaths.Values) { if (File.Exists(s)) { var fileName = Path.GetFileName(s); string finalSeed = seed; if (key != null) { finalSeed = key + fileName; } context[Context_MdfKey] = finalSeed; ShellConvert(s, "MDF", context); } } }); }); app.OnExecute(() => { uint?key = optKey.HasValue() ? optKey.ParsedValue : (uint?)null; uint?newKey = optNewKey.HasValue() ? optNewKey.ParsedValue : (uint?)null; foreach (var s in argPath.Values) { if (File.Exists(s)) { if (key != null && newKey != null) //Transfer { File.WriteAllBytes(Path.ChangeExtension(s, ".converted.psb"), PsbFile.Transfer(key.Value, newKey.Value, File.ReadAllBytes(s))); } else { Convert(key, s); } } } }); if (args.Length == 0) { app.ShowHelp(); Console.WriteLine("Convert all PSBs in current directory:"); AskForKey(); AskForNewKey(); DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory); uint count = 0; foreach (var file in di.EnumerateFiles("*.psb")) { if (NewKey != null) { try { File.WriteAllBytes(Path.ChangeExtension(file.FullName, ".converted.psb"), PsbFile.Transfer(Key.Value, NewKey.Value, File.ReadAllBytes(file.FullName))); count++; } catch (Exception e) { Console.WriteLine("Error: This file is not valid."); Console.WriteLine(e); } } else { if (Convert(Key, file.FullName)) { count++; } } } Console.WriteLine($"Completed! {count} files processed in total."); Console.WriteLine("Press ENTER to exit..."); Console.ReadLine(); return; } app.Execute(args); Console.WriteLine("Done."); }