private static async Task <bool> InjectMapIcons(List <MapDescriptor> mapDescriptors, DataFileSet cacheFileSet, DataFileSet tmpFileSet, DataFileSet riivFileSet, IProgress <ProgressInfo> progress, CancellationToken ct) { // first check if we need to inject any map icons in the first place. We do not need to if only vanilla map icons are used. bool allMapIconsVanilla = true; foreach (var mapDescriptor in mapDescriptors) { var mapIcon = mapDescriptor.MapIcon; if (string.IsNullOrEmpty(mapIcon)) { continue; } if (!VanillaDatabase.getVanillaTpl(mapIcon).Any()) { allMapIconsVanilla = false; break; } } if (allMapIconsVanilla) { return(true); } progress.Report("Extract game_sequence files..."); // setup the directories for the game sequence files /** maps the path of the various variants of the game_sequenceXXXXXXXX.arc files to their respective extraction path in the tmp directory */ var gameSequenceExtractPaths = new Dictionary <string, string>(); /** maps the path of the various variants of the game_sequenceXXXXXXXX.arc files to their respective temporary path for the converted xmlyt base path */ var gameSequenceToXmlytBasePaths = new Dictionary <string, string>(); /** maps the path of the various variants of the game_sequenceXXXXXXXX.arc files to their target path where they will be packed again */ var gameSequencePackPaths = new Dictionary <string, string>(); foreach (var entry in cacheFileSet.game_sequence_arc) { var locale = entry.Key; var gameSequencePath = entry.Value; var extractPath = Path.Combine(tmpFileSet.rootDir, Path.GetFileNameWithoutExtension(gameSequencePath)); Directory.CreateDirectory(Path.GetDirectoryName(extractPath)); gameSequenceExtractPaths.Add(gameSequencePath, extractPath); var xmlytPath = Path.Combine(tmpFileSet.rootDir, Path.GetFileNameWithoutExtension(gameSequencePath) + "."); Directory.CreateDirectory(Path.GetDirectoryName(xmlytPath)); gameSequenceToXmlytBasePaths.Add(gameSequencePath, xmlytPath); var packPath = riivFileSet.game_sequence_arc[locale]; Directory.CreateDirectory(Path.GetDirectoryName(packPath)); gameSequencePackPaths.Add(gameSequencePath, packPath); } foreach (var entry in cacheFileSet.game_sequence_wifi_arc) { var locale = entry.Key; var gameSequencePath = entry.Value; var extractPath = Path.Combine(tmpFileSet.rootDir, Path.GetFileNameWithoutExtension(gameSequencePath)); Directory.CreateDirectory(Path.GetDirectoryName(extractPath)); gameSequenceExtractPaths.Add(gameSequencePath, extractPath); var xmlytPath = Path.Combine(tmpFileSet.rootDir, Path.GetFileNameWithoutExtension(gameSequencePath) + "."); Directory.CreateDirectory(Path.GetDirectoryName(xmlytPath)); gameSequenceToXmlytBasePaths.Add(gameSequencePath, xmlytPath); var packPath = riivFileSet.game_sequence_wifi_arc[locale]; Directory.CreateDirectory(Path.GetDirectoryName(packPath)); gameSequencePackPaths.Add(gameSequencePath, packPath); } using (CancellationTokenSource source = new CancellationTokenSource()) { // start fake progress var fakeProgressTask = ProgressInfo.makeFakeProgress(ProgressInfo.makeSubProgress(progress, 2, 33), source.Token); // extract the arc files List <Task <string> > extractArcFileTasks = new List <Task <string> >(); foreach (var entry in gameSequenceExtractPaths) { string gameSequencePath = entry.Key; string gameSequenceExtractPath = entry.Value; extractArcFileTasks.Add(ExeWrapper.extractArcFile(gameSequencePath, gameSequenceExtractPath, ct, ProgressInfo.makeNoProgress(progress))); } await Task.WhenAll(extractArcFileTasks).ConfigureAwait(false); source.Cancel(); await fakeProgressTask.ConfigureAwait(false); } progress.Report("Convert map icons and inject them..."); using (CancellationTokenSource source = new CancellationTokenSource()) { // start fake progress var fakeProgressTask = ProgressInfo.makeFakeProgress(ProgressInfo.makeSubProgress(progress, 33, 66), source.Token); // convert the png files to tpl and copy them to the correct location Dictionary <string, string> mapIconToTplName = new Dictionary <string, string>(); List <Task> convertPngFileTasks = new List <Task>(); foreach (var mapDescriptor in mapDescriptors) { var mapIcon = mapDescriptor.MapIcon; if (string.IsNullOrEmpty(mapIcon)) { continue; } if (VanillaDatabase.getVanillaTpl(mapIcon).Any()) { // its a vanilla map icon -> dont convert and inject it VanillaDatabase.getVanillaTpl(mapIcon).IfPresent(value => mapIconToTplName[mapIcon] = value); } else { var mapIconPng = Path.Combine(tmpFileSet.param_folder, mapIcon + ".png"); var mapIconTpl = Path.ChangeExtension(mapIconPng, ".tpl"); var tplName = Ui_menu_19_00a.constructMapIconTplName(mapIcon); if (!mapIconToTplName.ContainsKey(mapIcon)) { mapIconToTplName.Add(mapIcon, tplName); } if (File.Exists(mapIconPng)) { Task task1 = ExeWrapper.convertPngToTpl(mapIconPng, mapIconTpl, ct, ProgressInfo.makeNoProgress(progress)); Task task2 = task1.ContinueWith(async(t1) => { await t1.ConfigureAwait(false); foreach (var entry in gameSequenceExtractPaths) { string gameSequencePath = entry.Key; string gameSequenceExtractPath = entry.Value; var mapIconTplCopy = Path.Combine(gameSequenceExtractPath, "arc", "timg", tplName); File.Copy(mapIconTpl, mapIconTplCopy, true); } }); convertPngFileTasks.Add(task2); } } } // convert the brlyt files to xmlyt, inject the map icons and convert it back List <Task> injectMapIconsInBrlytTasks = new List <Task>(); foreach (var entry in gameSequenceExtractPaths) { string gameSequencePath = entry.Key; string gameSequenceExtractPath = entry.Value; var brlytFile = Path.Combine(gameSequenceExtractPath, "arc", "blyt", "ui_menu_19_00a.brlyt"); string xmlytFile = gameSequenceToXmlytBasePaths[gameSequencePath] + Path.GetFileNameWithoutExtension(brlytFile) + ".xmlyt"; Task task1 = ExeWrapper.convertBryltToXmlyt(brlytFile, xmlytFile, ct, ProgressInfo.makeNoProgress(progress)); Task task2 = task1.ContinueWith(async(t1) => { await t1.ConfigureAwait(false); Ui_menu_19_00a.injectMapIconsLayout(xmlytFile, mapIconToTplName); }); Task task3 = task2.ContinueWith(async(t2) => { await t2.ConfigureAwait(false); await ExeWrapper.convertXmlytToBrylt(xmlytFile, brlytFile, ct, ProgressInfo.makeNoProgress(progress)); }); Task task4 = task3.ContinueWith(async(t3) => { await t3; // strange phenomenon: when converting the xmlyt files back to brlyt using benzin, sometimes the first byte is not correctly written. This fixes it as the first byte must be an 'R'. await Task.Delay(500); using (var stream = File.OpenWrite(brlytFile)) { stream.Seek(0, SeekOrigin.Begin); stream.WriteByte((byte)'R'); } // wait till the handle has been disposed properly await Task.Delay(500); }); injectMapIconsInBrlytTasks.Add(task4); } // convert the brlan files to xmlan, inject the map icons and convert it back List <Task> injectMapIconsInBrlanTasks = new List <Task>(); foreach (var entry in gameSequenceExtractPaths) { string gameSequencePath = entry.Key; string gameSequenceExtractPath = entry.Value; foreach (var brlanFile in Directory.GetFiles(Path.Combine(gameSequenceExtractPath, "arc", "anim"), "ui_menu_19_00a_Tag_*.brlan")) { string xmlanFile = gameSequenceToXmlytBasePaths[gameSequencePath] + Path.GetFileNameWithoutExtension(brlanFile) + ".xmlan"; Task task1 = ExeWrapper.convertBryltToXmlyt(brlanFile, xmlanFile, ct, ProgressInfo.makeNoProgress(progress)); Task task2 = task1.ContinueWith(async(t1) => { await t1.ConfigureAwait(false); Ui_menu_19_00a.injectMapIconsAnimation(xmlanFile, mapIconToTplName); }); Task task3 = task2.ContinueWith(async(t2) => { await t2.ConfigureAwait(false); await ExeWrapper.convertXmlytToBrylt(xmlanFile, brlanFile, ct, ProgressInfo.makeNoProgress(progress)); }); Task task4 = task3.ContinueWith(async(t3) => { await t3; // strange phenomenon: when converting the xmlyt files back to brlyt using benzin, sometimes the first byte is not correctly written. This fixes it as the first byte must be an 'R'. await Task.Delay(500); using (var stream = File.OpenWrite(brlanFile)) { stream.Seek(0, SeekOrigin.Begin); stream.WriteByte((byte)'R'); } // wait till the handle has been disposed properly await Task.Delay(500); }); injectMapIconsInBrlanTasks.Add(task4); } } await Task.WhenAll(injectMapIconsInBrlytTasks).ConfigureAwait(false); await Task.WhenAll(injectMapIconsInBrlanTasks).ConfigureAwait(false); await Task.WhenAll(convertPngFileTasks).ConfigureAwait(false); source.Cancel(); await fakeProgressTask.ConfigureAwait(false); } await Task.Delay(1000); progress.Report("Pack game_sequence files..."); using (CancellationTokenSource source = new CancellationTokenSource()) { // start fake progress var fakeProgressTask = ProgressInfo.makeFakeProgress(ProgressInfo.makeSubProgress(progress, 66, 100), source.Token); // pack the arc files List <Task <string> > packArcFileTasks = new List <Task <string> >(); foreach (var entry in gameSequenceExtractPaths) { string gameSequencePath = entry.Key; string gameSequenceExtractPath = entry.Value; string gameSequencePackPath = gameSequencePackPaths[gameSequencePath]; packArcFileTasks.Add(ExeWrapper.packDfolderToArc(gameSequenceExtractPath, gameSequencePackPath, ct, ProgressInfo.makeNoProgress(progress))); } await Task.WhenAll(packArcFileTasks).ConfigureAwait(false); source.Cancel(); await fakeProgressTask.ConfigureAwait(false); } await Task.Delay(1000); progress.Report(100); return(true); }
public static async Task <bool> Save(string inputFile, string outputFile, List <MapDescriptor> mapDescriptors, bool patchWiimmfi, IProgress <ProgressInfo> progress, CancellationToken ct, string cachePath = null, string riivPath = null, string tmpPath = null) { var packIso = IsImageFileExtension(outputFile); outputFile = DoPathCorrections(outputFile, true); inputFile = DoPathCorrections(inputFile, false); cachePath = Path.GetFullPath(GetCachePath(inputFile, cachePath)); if (IsImageFileExtension(cachePath)) { throw new ArgumentException("cachePath must be a valid extracted fortune street game disc directory"); } var cacheFileSet = new DataFileSet(cachePath); var riivFileSet = new DataFileSet(GetDefaultRiivPath(riivPath)); var tmpFileSet = new DataFileSet(GetDefaultTmpPath(tmpPath)); progress?.Report(new ProgressInfo(0, "Writing localization files...")); WriteLocalizationFiles(mapDescriptors, cacheFileSet, riivFileSet, patchWiimmfi && packIso); progress?.Report(new ProgressInfo(5, "Writing main.dol...")); await PatchMainDolAsync(mapDescriptors, cacheFileSet, riivFileSet, ProgressInfo.makeSubProgress(progress, 0, 6), ct); // lets get to the map icons await InjectMapIcons(mapDescriptors, cacheFileSet, tmpFileSet, riivFileSet, ProgressInfo.makeSubProgress(progress, 7, 40), ct).ConfigureAwait(false); await Task.Delay(500); var packIsoInputPath = cacheFileSet.rootDir; using (CancellationTokenSource source = new CancellationTokenSource()) { // start fake progress progress.Report(new ProgressInfo(45, "Copying the modified files...")); var fakeProgressTask = ProgressInfo.makeFakeProgress(ProgressInfo.makeSubProgress(progress, 45, packIso ? 60 : 99), source.Token); if (packIso) { if (ShouldKeepCache(inputFile)) { packIsoInputPath = Path.Combine(tmpFileSet.rootDir, Path.GetFileNameWithoutExtension("pack_" + outputFile)); DirectoryCopy(cacheFileSet.rootDir, packIsoInputPath, true, true, ProgressInfo.makeNoProgress(progress), ct); DirectoryCopy(riivFileSet.rootDir, packIsoInputPath, true, true, ProgressInfo.makeNoProgress(progress), ct); } else { DirectoryCopy(riivFileSet.rootDir, packIsoInputPath, true, true, ProgressInfo.makeNoProgress(progress), ct); } } else { if (cacheFileSet.rootDir != outputFile) { DirectoryCopy(cacheFileSet.rootDir, outputFile, true, true, ProgressInfo.makeNoProgress(progress), ct); } DirectoryCopy(riivFileSet.rootDir, outputFile, true, true, ProgressInfo.makeNoProgress(progress), ct); } source.Cancel(); await fakeProgressTask.ConfigureAwait(false); } await Task.Delay(500); if (packIso) { progress.Report(new ProgressInfo(60, "Packing ISO/WBFS file...")); await ExeWrapper.packFullIso(packIsoInputPath, outputFile, patchWiimmfi, ct, ProgressInfo.makeSubProgress(progress, 60, 100)).ConfigureAwait(true); if (patchWiimmfi) { await Task.Delay(500); progress.Report("Applying Wiimmfi..."); await ExeWrapper.applyWiimmfi(outputFile, ct, ProgressInfo.makeNoProgress(progress)).ConfigureAwait(false); } } else if (patchWiimmfi) { progress.Report("Warning: Wiimmfi is not applied as it can only be patched when packing into an iso/wbfs image."); } await Task.Delay(500); progress.Report(new ProgressInfo(100, "Done.")); return(true); }