public static MergerConfiguration ParseTOML(string tomlFilePath) { MergerConfiguration config = Toml.ReadFile <MergerConfiguration>(tomlFilePath); bool configOK = true; //validate the configuration foreach (InputInfo inputInfo in config.input) { foreach (List <int> region in inputInfo.ps3_regions) { //check for a region which is not length 2 if (region.Count != 2) { Console.WriteLine($"Error parsing info for {inputInfo.path}: Region should be length 2 but is length {region.Count}"); configOK = false; continue; } //check for a region where the start value is greater than the end value if (region[0] > region[1]) { Console.WriteLine($"Error parsing info for {inputInfo.path}: Start is greater than end [{region[0]},{region[1]}]"); configOK = false; continue; } } } return(configOK ? config : null); }
//wrapper to allow 'pausing' of program but still garbage collect everything to force files to write-out static void RunProgram() { Console.WriteLine("If japanese characters show as ???? please change your console font to MS Gothic or similar."); //MUST set this so that diff tool can output proper unicode (otherwise output is scrambled) //and so can see japanese characters (you might need to change your console font too to MS Gothic or similar) Console.OutputEncoding = System.Text.Encoding.UTF8; MergerConfiguration config = HintParser.ParseTOML("conf.toml"); if (config == null) { Console.WriteLine("Can't continue - config file is not valid!"); PauseThenErrorExit(); } else { Console.WriteLine("Config file is valid."); } Directory.SetCurrentDirectory(config.working_directory); //Read in/merge the xml file according to the config string untranslatedXMLFilePath = null; if (File.Exists(config.ps3_xml_path)) { untranslatedXMLFilePath = config.ps3_xml_path; } else if (Directory.Exists(config.ps3_xml_path)) { FileConcatenator.MergeFilesInFolder(config.ps3_xml_path, config.ps3_merged_output_path); untranslatedXMLFilePath = config.ps3_merged_output_path; } else { Console.WriteLine($"Can't find ps3 input file/folder {Path.GetFullPath(config.ps3_xml_path)}"); PauseThenErrorExit(); } //begin processing List <PS3DialogueInstruction> pS3DialogueInstructionsPreFilter = PS3XMLReader.GetPS3DialoguesFromXML(untranslatedXMLFilePath); // >>>> Merge ModCallScriptSection: pre-process each file in the pre-input folder, ignoring sub scripts // >>>> this inserts the subscripts inline into the script Regex emptyMainRegex = new Regex(@"void\s*main\(\s*\)\s*{\s*}"); foreach (string pathOfPossibleScript in Directory.EnumerateFiles(config.pre_input_folder, "*.*", SearchOption.AllDirectories)) { // Skip scripts which have an empty main file - these are sub scripts string fileText = File.ReadAllText(pathOfPossibleScript); if (emptyMainRegex.Match(fileText).Success) { Console.WriteLine($"Skipping script {pathOfPossibleScript} as it looks like a Sub-Script"); continue; } string filename = Path.GetFileName(pathOfPossibleScript); // >>>> Merge ModCallScriptSection: Before loading the manga gamer dialog, copy in any ModCallScriptSection(...) calls. This will be undone at a later stage List <string> mergedScriptLines = ForkingScriptMerger.MergeForkedScript(config.pre_input_folder, filename, true); File.WriteAllLines(Path.Combine(config.input_folder, filename), mergedScriptLines); } //TODO: scan for files, generate dummy input infos for files which haven't got specified regions. //ProcessSingleFile should then attempt to find the correct regions for those files and dump to toml file //TODO: clean up console output HashSet <string> filePathsToGetStartEnd = new HashSet <string>(); //note: this path includes the input folder name eg "input/test.txt" foreach (string fileInInputFolder in Directory.EnumerateFiles(config.input_folder, "*.*", SearchOption.AllDirectories)) { filePathsToGetStartEnd.Add(Path.GetFullPath(fileInInputFolder)); } Counter counter = new Counter(); List <PartialSubScriptToMerge> forkedScriptContentToMergeList = new List <PartialSubScriptToMerge>(); foreach (InputInfo inputInfo in config.input) { string tomlInputFilePathNormalized = Path.GetFullPath(Path.Combine(config.input_folder, inputInfo.path)); if (filePathsToGetStartEnd.Contains(tomlInputFilePathNormalized)) { Console.WriteLine($"\n[ TOML OK ]: {tomlInputFilePathNormalized} found in config file with region {StringUtils.PrettyPrintListOfListToString(inputInfo.ps3_regions)}"); filePathsToGetStartEnd.Remove(tomlInputFilePathNormalized); forkedScriptContentToMergeList.AddRange( ProcessSingleFile(pS3DialogueInstructionsPreFilter, config, inputInfo, new List <InputInfo>(), counter) ); } } //Unmerge all the sub-scripts (zonik_....txt) ForkingScriptMerger.UnMergeForkedScripts(config.pre_input_folder, config.output_folder, forkedScriptContentToMergeList); //Write out the counter statistics counter.WriteStatistics(Path.Combine(config.output_folder, "counter_statistics.txt")); //Save to a file so it can be copied into toml file (if already correct) var tempCounter = new Counter(); using (StreamWriter sw = FileUtils.CreateDirectoriesAndOpen(config.guessed_matches, FileMode.Create)) { List <InputInfo> guessedInputInfos = new List <InputInfo>(); foreach (string filePathToGetStartEnd in filePathsToGetStartEnd) { Console.WriteLine($"\n[TOML MISSING]: Start/End of [{filePathToGetStartEnd}] not specified."); Console.WriteLine($"Will try best to do matching, but suggest manually inputting start and end."); string relativePath = FileUtils.GetRelativePath(filePathToGetStartEnd, Path.GetFullPath(config.input_folder)); // Since no ps3 region specified, should just search the whole PS3 xml InputInfo wholeFileInputInfo = new InputInfo { path = relativePath, ps3_regions = new List <List <int> >(), }; ProcessSingleFile(pS3DialogueInstructionsPreFilter, config, wholeFileInputInfo, guessedInputInfos, tempCounter); foreach (InputInfo info in guessedInputInfos) { sw.WriteLine("# Autogenerated Match"); sw.WriteLine("[[input]]"); sw.WriteLine($"filename = {info.path}"); sw.WriteLine($"ps3_regions = {StringUtils.PrettyPrintListOfListToString(info.ps3_regions)}"); sw.WriteLine(); sw.Flush(); } guessedInputInfos.Clear(); } } }
/// <summary> /// processes a single mangagamer script, attempting to merge the matching ps3 instructions /// </summary> /// <param name="pS3DialogueInstructionsPreFilter"></param> /// <param name="config"></param> /// <param name="mgInfo"></param> /// <param name="guessedInputInfos"></param> static List <PartialSubScriptToMerge> ProcessSingleFile( List <PS3DialogueInstruction> pS3DialogueInstructionsPreFilter, MergerConfiguration config, InputInfo mgInfo, List <InputInfo> guessedInputInfos, Counter counter) { string fullPath = Path.Combine(config.input_folder, mgInfo.path); string pathNoExt = Path.GetFileNameWithoutExtension(fullPath); string debug_side_by_side_diff_path_MG = Path.Combine(config.output_folder, pathNoExt + "_side_by_side_debug.html"); string debug_alignment_statistics = Path.Combine(config.output_folder, pathNoExt + "_statistics_debug.txt"); List <PS3DialogueInstruction> pS3DialogueInstructions = GetFilteredPS3Instructions(pS3DialogueInstructionsPreFilter, mgInfo.ps3_regions); //load all the mangagamer lines from the mangagamer file List <MangaGamerDialogue> allMangaGamerDialogue = MangaGamerScriptReader.GetDialogueLinesFromMangaGamerScript(fullPath, out List <string> mg_leftovers); //PS3 Dialogue fragments List <PS3DialogueFragment> ps3DialogueFragments = new List <PS3DialogueFragment>(); int ps3DialogueIndex = 0; foreach (PS3DialogueInstruction ps3Dialogue in pS3DialogueInstructions) { List <string> splitDialogueStrings = PS3DialogueTools.SplitPS3StringNoNames(ps3Dialogue.data); PS3DialogueFragment previousPS3DialogueFragment = null; for (int i = 0; i < splitDialogueStrings.Count; i++) { //dummy instructions index into the ps3DialogueList (for now...) PS3DialogueFragment ps3DialogueFragment = new PS3DialogueFragment(ps3Dialogue, splitDialogueStrings[i], i, previousPS3DialogueFragment); ps3DialogueFragments.Add(ps3DialogueFragment); previousPS3DialogueFragment = ps3DialogueFragment; } ps3DialogueIndex++; } //If no ps3 regions specified, scan for regions, then print and let user fill in? if (mgInfo.ps3_regions.Count == 0) { Console.WriteLine($"The file [{mgInfo.path}] does not have the PS3 region marked in the conf.toml file!"); Console.WriteLine($"Scanning for PS3 region..."); //print the first few and last mangagamer instructions //skip if length too small? Console.WriteLine("------- Finding first 5 entries -------"); int?startResult = AnalyseEntries(ps3DialogueFragments, allMangaGamerDialogue, amount: 10, isStart: true); if (startResult.HasValue) { Console.WriteLine($"Best guess at start PS3 ID: {startResult.Value}"); } else { Console.WriteLine("Not sure about start PS3 ID. Please inspect manually."); } Console.WriteLine("------- Finding last 5 entries -------"); int?endResult = AnalyseEntries(ps3DialogueFragments, allMangaGamerDialogue, amount: 10, isStart: false); if (endResult.HasValue) { Console.WriteLine($"Best guess at last PS3 ID: {endResult.Value}"); } else { Console.WriteLine("Not sure about last PS3 ID. Please inspect manually."); } string result_start_id = "<START_REGION>"; string result_end_id = "<END_REGION>"; if (startResult.HasValue && endResult.HasValue) { Console.WriteLine("AUTOREGION SUCCESS: You can copy this into the conf.toml file\n\n"); result_start_id = startResult.Value.ToString(); result_end_id = endResult.Value.ToString(); } else { Console.WriteLine($"AUTOREGION FAIL: Region couldn't be determined confidently. Please use the above information and the ps3 script" + $"to determine the PS3 region manually, then place the results in the conf.toml file as per below"); } Console.WriteLine("[[input]]"); Console.WriteLine($@"path = ""{mgInfo.path}"""); Console.WriteLine($"ps3_regions = [[{result_start_id}, {result_end_id}]]"); Console.WriteLine("No output will be generated for this script until the program is run again."); Console.WriteLine("Press ENTER to move to the next script..."); Console.ReadKey(); return(new List <PartialSubScriptToMerge>()); } //Diff the dialogue List <AlignmentPoint> allAlignmentPoints = Differ.DoDiff(config.temp_folder, allMangaGamerDialogue, ps3DialogueFragments, debugFilenamePrefix: pathNoExt); //Sanity check the alignment points by making sure there aren't missing any values SanityCheckAlignmentPoints(allAlignmentPoints, allMangaGamerDialogue, ps3DialogueFragments); //trim alignment points to reduce output List <AlignmentPoint> alignmentPoints = config.trim_after_diff ? TrimAlignmentPoints(allAlignmentPoints) : allAlignmentPoints; //Write statistics on how well matched the alignment points are WriteAlignmentStatistics(alignmentPoints, debug_alignment_statistics); //DEBUG: generate the side-by-side diff DifferDebugUtilities.PrintHTMLSideBySideDiff(alignmentPoints, debug_side_by_side_diff_path_MG); //Insert PS3 instructions string mergedOutputPath = Path.Combine(config.output_folder, pathNoExt + "_merged.xml.txt"); SaveMergedMGScript(alignmentPoints, mergedOutputPath, mg_leftovers); // >>>> UnMerge ModCallScriptSection: Before using the results, we need to reverse the step we did earlier, by unmerging any merged files back into multiple files. //Use the inserted instructions string finalOutputWithMergedForkedScripts = Path.Combine(config.output_folder, pathNoExt + ".txt"); MergedScriptPostProcessing.PostProcessingMain.InsertMGLinesUsingPS3XML(mergedOutputPath, finalOutputWithMergedForkedScripts, config, counter); List <PartialSubScriptToMerge> partialSubScriptsToMerge = ForkingScriptMerger.GetForkedScriptContentFromMergedScript(config.pre_input_folder, finalOutputWithMergedForkedScripts); ForkingScriptMerger.RemoveForkedScriptContentFromMergedScript(finalOutputWithMergedForkedScripts); return(partialSubScriptsToMerge); }