private void generateRepaceFilesMapping(IniData ini, string modpath) { var dirs = Directory.GetDirectories(modpath); foreach (var dir in dirs) { //automap var dirname = Path.GetFileName(dir); var headername = ModMakerCompiler.defaultFoldernameToHeader(dirname).ToString(); ini[headername][@"moddir"] = dirname; if (dirname != @"BALANCE_CHANGES") { ini[headername][@"newfiles"] = @"CookedPCConsole"; string inGameDestdir; if (dirname == @"BASEGAME") { inGameDestdir = @"BIOGame/CookedPCConsole"; } else { //DLC inGameDestdir = $@"BIOGame/DLC/{ModMakerCompiler.ModmakerChunkNameToDLCFoldername(dirname)}/CookedPCConsole"; } ini[headername][@"replacefiles"] = inGameDestdir; ini[headername][@"gamedirectorystructure"] = @"true"; } else { ini[headername][@"newfiles"] = @"ServerCoalesced.bin"; //BALANCE_CHANGES } } }
private void UpdateModMakerMod(OnlineContent.ModMakerModUpdateInfo mui) { //throw new NotImplementedException(); NamedBackgroundWorker nbw = new NamedBackgroundWorker(@"ModmakerModUpdaterThread-" + mui.mod.ModName); nbw.WorkerReportsProgress = true; nbw.ProgressChanged += (a, b) => { if (b.UserState is double d) { mainwindow.TaskBarItemInfoHandler.ProgressValue = d; } }; nbw.DoWork += (a, b) => { mui.DownloadButtonText = M3L.GetString(M3L.string_compiling); OperationInProgress = true; mui.UpdateInProgress = true; mui.Indeterminate = false; mui.UIStatusString = M3L.GetString(M3L.string_downloadingDelta); var normalEndpoint = OnlineContent.ModmakerModsEndpoint + mui.ModMakerId; var lzmaEndpoint = normalEndpoint + @"&method=lzma"; string modDelta = null; //Try LZMA first try { var download = OnlineContent.DownloadToMemory(lzmaEndpoint); if (download.errorMessage == null) { mui.UIStatusString = M3L.GetString(M3L.string_decompressingDelta); // OK var decompressed = SevenZipHelper.LZMA.DecompressLZMAFile(download.result.ToArray()); modDelta = Encoding.UTF8.GetString(decompressed); } else { Log.Error(@"Error downloading lzma mod delta to memory: " + download.errorMessage); } } catch (Exception e) { Log.Error(@"Error downloading LZMA mod delta to memory: " + e.Message); } if (modDelta == null) { //failed to download LZMA. var download = OnlineContent.DownloadToMemory(normalEndpoint); if (download.errorMessage == null) { //OK modDelta = Encoding.UTF8.GetString(download.result.ToArray()); } else { Log.Error(@"Error downloading decompressed mod delta to memory: " + download.errorMessage); } } void setOverallMax(int max) { mui.OverallProgressMax = max; } void setOverallValue(int current) { mui.OverallProgressValue = current; nbw.ReportProgress(0, current * 1.0 / mui.OverallProgressMax); if (current > mui.OverallProgressMax) { Debugger.Break(); } } void setCurrentTaskString(string str) { mui.UIStatusString = str; } if (modDelta != null) { var compiler = new ModMakerCompiler(mui.ModMakerId); //compiler.SetCurrentMaxCallback = SetCurrentMax; //compiler.SetCurrentValueCallback = SetCurrentProgressValue; compiler.SetOverallMaxCallback = setOverallMax; compiler.SetOverallValueCallback = setOverallValue; //compiler.SetCurrentTaskIndeterminateCallback = SetCurrentTaskIndeterminate; compiler.SetCurrentTaskStringCallback = setCurrentTaskString; //compiler.SetModNameCallback = SetModNameOrDownloadText; //compiler.SetCompileStarted = CompilationInProgress; //compiler.SetModNotFoundCallback = ModNotFound; Mod m = compiler.DownloadAndCompileMod(modDelta); if (m != null) { try { File.WriteAllText(System.IO.Path.Combine(Utilities.GetModmakerDefinitionsCache(), mui.ModMakerId + @".xml"), modDelta); } catch (Exception e) { Log.Error(@"Couldn't cache modmaker xml file: " + e.Message); } mui.DownloadButtonText = M3L.GetString(M3L.string_updated); mui.UIStatusString = M3L.GetString(M3L.string_interp_modMakerCodeX, mui.ModMakerId); mui.UpdateInProgress = false; mui.CanUpdate = false; AnyModUpdated = true; } else { mui.UpdateInProgress = false; mui.DownloadButtonText = M3L.GetString(M3L.string_compilingFailed); mui.UpdateInProgress = false; } } }; nbw.RunWorkerCompleted += (a, b) => { if (b.Error != null) { Log.Error($@"Exception occured in {nbw.Name} thread: {b.Error.Message}"); } Analytics.TrackEvent(@"Updated mod", new Dictionary <string, string>() { { @"Type", @"ModMaker" }, { @"ModName", mui.mod.ModName }, { @"Result", mui.CanUpdate ? @"Success" : @"Failed" } }); mainwindow.TaskBarItemInfoHandler.ProgressState = TaskbarItemProgressState.None; OperationInProgress = false; CommandManager.InvalidateRequerySuggested(); }; mainwindow.TaskBarItemInfoHandler.ProgressValue = 0; mainwindow.TaskBarItemInfoHandler.ProgressState = TaskbarItemProgressState.Normal; nbw.RunWorkerAsync(); }
private void UpdateModMakerMod(OnlineContent.ModMakerModUpdateInfo mui) { //throw new NotImplementedException(); NamedBackgroundWorker bw = new NamedBackgroundWorker(@"ModmakerModUpdaterThread-" + mui.mod.ModName); bw.DoWork += (a, b) => { mui.DownloadButtonText = M3L.GetString(M3L.string_compiling); OperationInProgress = true; mui.UpdateInProgress = true; mui.Indeterminate = false; mui.UIStatusString = M3L.GetString(M3L.string_downloadingDelta); var normalEndpoint = OnlineContent.ModmakerModsEndpoint + mui.ModMakerId; var lzmaEndpoint = normalEndpoint + @"&method=lzma"; string modDelta = null; //Try LZMA first try { var download = OnlineContent.DownloadToMemory(lzmaEndpoint); if (download.errorMessage == null) { mui.UIStatusString = M3L.GetString(M3L.string_decompressingDelta); // OK var decompressed = SevenZipHelper.LZMA.DecompressLZMAFile(download.result.ToArray()); modDelta = Encoding.UTF8.GetString(decompressed); // File.WriteAllText(@"C:\users\mgamerz\desktop\decomp.txt", modDelta); } else { Log.Error(@"Error downloading lzma mod delta to memory: " + download.errorMessage); } } catch (Exception e) { Log.Error(@"Error downloading LZMA mod delta to memory: " + e.Message); } if (modDelta == null) { //failed to download LZMA. var download = OnlineContent.DownloadToMemory(normalEndpoint); if (download.errorMessage == null) { //OK modDelta = Encoding.UTF8.GetString(download.result.ToArray()); } else { Log.Error(@"Error downloading decompressed mod delta to memory: " + download.errorMessage); } } void setOverallMax(int max) { mui.OverallProgressMax = max; } void setOverallValue(int current) { mui.OverallProgressValue = current; if (current > mui.OverallProgressMax) { Debugger.Break(); } } void setCurrentTaskString(string str) { mui.UIStatusString = str; } if (modDelta != null) { var compiler = new ModMakerCompiler(mui.ModMakerId); //compiler.SetCurrentMaxCallback = SetCurrentMax; //compiler.SetCurrentValueCallback = SetCurrentProgressValue; compiler.SetOverallMaxCallback = setOverallMax; compiler.SetOverallValueCallback = setOverallValue; //compiler.SetCurrentTaskIndeterminateCallback = SetCurrentTaskIndeterminate; compiler.SetCurrentTaskStringCallback = setCurrentTaskString; //compiler.SetModNameCallback = SetModNameOrDownloadText; //compiler.SetCompileStarted = CompilationInProgress; //compiler.SetModNotFoundCallback = ModNotFound; Mod m = compiler.DownloadAndCompileMod(modDelta); File.WriteAllText(System.IO.Path.Combine(Utilities.GetModmakerDefinitionsCache(), mui.ModMakerId + @".xml"), modDelta); mui.DownloadButtonText = M3L.GetString(M3L.string_updated); mui.UIStatusString = M3L.GetString(M3L.string_interp_modMakerCodeX, mui.ModMakerId); mui.UpdateInProgress = false; mui.CanUpdate = false; AnyModUpdated = true; //b.Result = m; } }; bw.RunWorkerCompleted += (a, b) => { OperationInProgress = false; CommandManager.InvalidateRequerySuggested(); }; bw.RunWorkerAsync(); }
private void StartCompiler() { CompileInProgress = true; Settings.Save(); //Persist controller mixin option, keybinds injection NamedBackgroundWorker nbw = new NamedBackgroundWorker(@"ModmakerCompiler"); nbw.DoWork += (a, b) => { string modDelta = null; if (int.TryParse(ModMakerCode, out var code)) { DownloadAndModNameText = @"Downloading mod delta from ME3Tweaks"; var normalEndpoint = OnlineContent.ModmakerModsEndpoint + code; var lzmaEndpoint = normalEndpoint + @"&method=lzma"; //Try LZMA first try { var download = OnlineContent.DownloadToMemory(lzmaEndpoint, (done, total) => { if (total != -1) { var suffix = $@" {(done * 100.0 / total).ToString(@"0")}%"; //do not localize DownloadAndModNameText = M3L.GetString(M3L.string_downloadingModDeltaFromME3Tweaks) + suffix; } else { DownloadAndModNameText = M3L.GetString(M3L.string_downloadingModDeltaFromME3Tweaks); } }); if (download.errorMessage == null) { DownloadAndModNameText = M3L.GetString(M3L.string_decompressingDelta); // OK var decompressed = SevenZipHelper.LZMA.DecompressLZMAFile(download.result.ToArray()); modDelta = Encoding.UTF8.GetString(decompressed); // File.WriteAllText(@"C:\users\mgamerz\desktop\decomp.txt", modDelta); } else { Log.Error(@"Error downloading lzma mod delta to memory: " + download.errorMessage); } } catch (Exception e) { Log.Error(@"Error downloading LZMA mod delta to memory: " + e.Message); } if (modDelta == null) { //failed to download LZMA. var download = OnlineContent.DownloadToMemory(normalEndpoint, (done, total) => { var suffix = $" {(done * 100.0 / total).ToString(@"0")}%"; //do not localize DownloadAndModNameText = M3L.GetString(M3L.string_downloadingModDeltaFromME3Tweaks) + suffix; }); if (download.errorMessage == null) { //OK modDelta = Encoding.UTF8.GetString(download.result.ToArray()); } else { Log.Error(@"Error downloading decompressed mod delta to memory: " + download.errorMessage); } } } else if (File.Exists(LocalFilePath)) { modDelta = File.ReadAllText(LocalFilePath); } if (modDelta != null) { KeepOpenWhenThreadFinishes = false; var compiler = new ModMakerCompiler(code); compiler.SetCurrentMaxCallback = SetCurrentMax; compiler.SetCurrentValueCallback = SetCurrentProgressValue; compiler.SetOverallMaxCallback = SetOverallMax; compiler.SetOverallValueCallback = SetOverallValue; compiler.SetCurrentTaskIndeterminateCallback = SetCurrentTaskIndeterminate; compiler.SetCurrentTaskStringCallback = SetCurrentTaskString; compiler.SetModNameCallback = SetModNameOrDownloadText; compiler.SetCompileStarted = CompilationInProgress; compiler.SetModNotFoundCallback = ModNotFound; compiler.NotifySomeDLCIsMissing = NotifySomeDLCIsMissing; Mod m = compiler.DownloadAndCompileMod(modDelta); if (m != null && !LocalFileOption) { var sanitizedname = Utilities.SanitizePath(m.ModName); File.WriteAllText(Path.Combine(Utilities.GetModmakerDefinitionsCache(), $@"{code}-{sanitizedname}.xml"), modDelta); } b.Result = m; } }; nbw.RunWorkerCompleted += (a, b) => { if (b.Error != null) { Log.Error($@"Exception occured in {nbw.Name} thread: {b.Error.Message}"); } CompileInProgress = false; if (!KeepOpenWhenThreadFinishes && b.Result is Mod m) { OnClosing(new DataEventArgs(m)); } else { CloseProgressPanel(); ShowCloseButton = true; } CommandManager.InvalidateRequerySuggested(); }; nbw.RunWorkerAsync(); }
private void CompileIntoGame() { NamedBackgroundWorker nbw = new NamedBackgroundWorker(@"MixinManager CompileIntoGameThread"); List <string> failedApplications = new List <string>(); nbw.DoWork += (a, b) => { BottomLeftMessage = M3L.GetString(M3L.string_compilingMixins); OperationInProgress = true; //DEBUG STUFF #if DEBUG int numCoresToApplyWith = 1; #else var numCoresToApplyWith = Environment.ProcessorCount; if (numCoresToApplyWith > 4) { numCoresToApplyWith = 4; //no more than 4 as this uses a lot of memory } #endif var mixins = AvailableOfficialMixins.Where(x => x.UISelectedForUse).ToList(); MixinHandler.LoadPatchDataForMixins(mixins); //before dynamic void failedApplicationCallback(string str) { failedApplications.Add(str); } var compilingListsPerModule = MixinHandler.GetMixinApplicationList(mixins, failedApplicationCallback); if (failedApplications.Any()) { //Error building list Log.Information(@"Aborting mixin install due to incompatible selection of mixins"); return; } ProgressBarMax = mixins.Count(); ProgressBarValue = 0; int numdone = 0; void completedSingleApplicationCallback() { var val = Interlocked.Increment(ref numdone); ProgressBarValue = val; } //Mixins are ready to be applied Parallel.ForEach(compilingListsPerModule, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount > numCoresToApplyWith ? numCoresToApplyWith : Environment.ProcessorCount }, mapping => { var dlcFolderName = ModMakerCompiler.ModmakerChunkNameToDLCFoldername(mapping.Key.ToString()); //var outdir = Path.Combine(modpath, ModMakerCompiler.HeaderToDefaultFoldername(mapping.Key), @"CookedPCConsole"); //Directory.CreateDirectory(outdir); if (mapping.Key == ModJob.JobHeader.BASEGAME) { //basegame foreach (var file in mapping.Value) { try { using var vanillaPackageAsStream = VanillaDatabaseService.FetchBasegameFile(Mod.MEGame.ME3, Path.GetFileName(file.Key)); //packageAsStream.WriteToFile(@"C:\users\dev\desktop\compressed.pcc"); using var decompressedStream = MEPackage.GetDecompressedPackageStream(vanillaPackageAsStream, true); decompressedStream.Position = 0; var vanillaPackage = MEPackageHandler.OpenMEPackage(decompressedStream, $@"Vanilla - {Path.GetFileName(file.Key)}"); //decompressedStream.WriteToFile(@"C:\users\dev\desktop\decompressed.pcc"); using var mixinModifiedStream = MixinHandler.ApplyMixins(decompressedStream, file.Value, completedSingleApplicationCallback, failedApplicationCallback); mixinModifiedStream.Position = 0; var modifiedPackage = MEPackageHandler.OpenMEPackage(mixinModifiedStream, $@"Mixin Modified - {Path.GetFileName(file.Key)}"); // three way merge: get target stream var targetFile = Path.Combine(MEDirectories.CookedPath(SelectedInstallTarget), Path.GetFileName(file.Key)); var targetPackage = MEPackageHandler.OpenMEPackage(targetFile); var merged = ThreeWayPackageMerge.AttemptMerge(vanillaPackage, modifiedPackage, targetPackage); if (merged) { targetPackage.save(); Log.Information("Three way merge succeeded for " + targetFile); } else { Log.Error("Could not merge three way merge into " + targetFile); } //var outfile = Path.Combine(outdir, Path.GetFileName(file.Key)); //package.save(outfile, false); // don't compress //finalStream.WriteToFile(outfile); //File.WriteAllBytes(outfile, finalStream.ToArray()); } catch (Exception e) { var mixinsStr = string.Join(@", ", file.Value.Select(x => x.PatchName)); Log.Error($@"Error in mixin application for file {file.Key}: {e.Message}"); failedApplicationCallback(M3L.GetString(M3L.string_interp_errorApplyingMixinsForFile, mixinsStr, file.Key, e.Message)); } } } else { //dlc var dlcPackage = VanillaDatabaseService.FetchVanillaSFAR(dlcFolderName); //do not have to open file multiple times. var targetCookedPCDir = Path.Combine(MEDirectories.DLCPath(SelectedInstallTarget), dlcFolderName, @"CookedPCConsole"); var sfar = mapping.Key == ModJob.JobHeader.TESTPATCH ? Utilities.GetTestPatchPath(SelectedInstallTarget) : Path.Combine(targetCookedPCDir, @"Default.sfar"); bool unpacked = new FileInfo(sfar).Length == 32; DLCPackage targetDLCPackage = unpacked ? null : new DLCPackage(sfar); //cache SFAR target foreach (var file in mapping.Value) { try { using var vanillaPackageAsStream = VanillaDatabaseService.FetchFileFromVanillaSFAR(dlcFolderName, file.Key, forcedDLC: dlcPackage); using var decompressedStream = MEPackage.GetDecompressedPackageStream(vanillaPackageAsStream); decompressedStream.Position = 0; var vanillaPackage = MEPackageHandler.OpenMEPackage(decompressedStream, $@"VanillaDLC - {Path.GetFileName(file.Key)}"); using var mixinModifiedStream = MixinHandler.ApplyMixins(decompressedStream, file.Value, completedSingleApplicationCallback, failedApplicationCallback); mixinModifiedStream.Position = 0; var modifiedPackage = MEPackageHandler.OpenMEPackage(mixinModifiedStream, $@"Mixin Modified - {Path.GetFileName(file.Key)}"); // three way merge: get target stream // must see if DLC is unpacked first MemoryStream targetFileStream = null; //Packed if (unpacked) { targetFileStream = new MemoryStream(File.ReadAllBytes(Path.Combine(targetCookedPCDir, file.Key))); } else { targetFileStream = VanillaDatabaseService.FetchFileFromVanillaSFAR(dlcFolderName, Path.GetFileName(file.Key), forcedDLC: targetDLCPackage); } var targetPackage = MEPackageHandler.OpenMEPackage(targetFileStream, $@"Target package {dlcFolderName} - {file.Key}, from SFAR: {unpacked}"); var merged = ThreeWayPackageMerge.AttemptMerge(vanillaPackage, modifiedPackage, targetPackage); if (merged) { if (unpacked) { targetPackage.save(); Log.Information("Three way merge succeeded for " + targetPackage.FilePath); } else { var finalSTream = targetPackage.saveToStream(); targetDLCPackage.ReplaceEntry(finalSTream.ToArray(), targetDLCPackage.FindFileEntry(Path.GetFileName(file.Key))); Log.Information("Three way merge succeeded for " + targetPackage.FileSourceForDebugging); } } else { Log.Error("Could not merge three way merge into " + targetFileStream); } } catch (Exception e) { var mixinsStr = string.Join(@", ", file.Value.Select(x => x.PatchName)); Log.Error($@"Error in mixin application for file {file.Key}: {e.Message}"); failedApplicationCallback(M3L.GetString(M3L.string_interp_errorApplyingMixinsForFile, mixinsStr, file.Key, e.Message)); } //finalStream.WriteToFile(outfile); } } }); MixinHandler.FreeME3TweaksPatchData(); var percent = 0; //this is used to save a localization BottomLeftMessage = $"Running AutoTOC on game {percent}%"; //Run autotoc void tocingUpdate(int percent) { BottomLeftMessage = $"Running AutoTOC on game {percent}%"; } AutoTOC.RunTOCOnGameTarget(SelectedInstallTarget, tocingUpdate); //Generate moddesc //IniData ini = new IniData(); //ini[@"ModManager"][@"cmmver"] = App.HighestSupportedModDesc.ToString(CultureInfo.InvariantCulture); //prevent commas //ini[@"ModInfo"][@"game"] = @"ME3"; //ini[@"ModInfo"][@"modname"] = modname; //ini[@"ModInfo"][@"moddev"] = App.AppVersionHR; //ini[@"ModInfo"][@"moddesc"] = M3L.GetString(M3L.string_compiledFromTheFollowingMixins); //ini[@"ModInfo"][@"modver"] = @"1.0"; //generateRepaceFilesMapping(ini, modpath); //File.WriteAllText(Path.Combine(modpath, @"moddesc.ini"), ini.ToString()); }; nbw.RunWorkerCompleted += (a, b) => { OperationInProgress = false; ClearMixinHandler(); if (failedApplications.Count > 0) { var ld = new ListDialog(failedApplications, M3L.GetString(M3L.string_failedToApplyAllMixins), M3L.GetString(M3L.string_theFollowingMixinsFailedToApply), mainwindow); ld.ShowDialog(); } /*if (modpath != null) * { * OnClosing(new DataEventArgs(modpath)); * } * else * {*/ BottomLeftMessage = "Mixins installed, maybe. Check logs"; //} }; CompilePanelButton.IsOpen = false; nbw.RunWorkerAsync(); }
private void CompileAsNewMod() { NamedBackgroundWorker nbw = new NamedBackgroundWorker(@"MixinManager CompileAsNewModThread"); List <string> failedApplications = new List <string>(); var modname = NewModName; var modpath = Path.Combine(Utilities.GetME3ModsDirectory(), Utilities.SanitizePath(modname)); var result = M3L.ShowDialog(mainwindow, M3L.GetString(M3L.string_interp_dialogCreatingNewModWithExistingName, NewModName, modpath), M3L.GetString(M3L.string_modAlreadyExists), MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (result == MessageBoxResult.No) { Log.Information(@"User has aborted mixin compilation due to same-named mod existing"); return; //abort. } nbw.DoWork += (a, b) => { BottomLeftMessage = M3L.GetString(M3L.string_compilingMixins); OperationInProgress = true; //DEBUG STUFF #if DEBUG int numCoresToApplyWith = 1; #else var numCoresToApplyWith = Environment.ProcessorCount; if (numCoresToApplyWith > 4) { numCoresToApplyWith = 4; //no more than 4 as this uses a lot of memory } #endif var mixins = AvailableOfficialMixins.Where(x => x.UISelectedForUse).ToList(); MixinHandler.LoadPatchDataForMixins(mixins); //before dynamic void failedApplicationCallback(string str) { failedApplications.Add(str); } var compilingListsPerModule = MixinHandler.GetMixinApplicationList(mixins, failedApplicationCallback); if (failedApplications.Any()) { //Error building list modpath = null; Log.Information(@"Aborting mixin compiling due to incompatible selection of mixins"); return; } if (Directory.Exists(modpath)) { Utilities.DeleteFilesAndFoldersRecursively(modpath); } ProgressBarMax = mixins.Count(); ProgressBarValue = 0; int numdone = 0; void completedSingleApplicationCallback() { var val = Interlocked.Increment(ref numdone); ProgressBarValue = val; } //Mixins are ready to be applied Parallel.ForEach(compilingListsPerModule, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount > numCoresToApplyWith ? numCoresToApplyWith : Environment.ProcessorCount }, mapping => { var dlcFolderName = ModMakerCompiler.ModmakerChunkNameToDLCFoldername(mapping.Key.ToString()); var outdir = Path.Combine(modpath, ModMakerCompiler.HeaderToDefaultFoldername(mapping.Key), @"CookedPCConsole"); Directory.CreateDirectory(outdir); if (mapping.Key == ModJob.JobHeader.BASEGAME) { //basegame foreach (var file in mapping.Value) { try { using var packageAsStream = VanillaDatabaseService.FetchBasegameFile(Mod.MEGame.ME3, Path.GetFileName(file.Key)); //packageAsStream.WriteToFile(@"C:\users\dev\desktop\compressed.pcc"); using var decompressedStream = MEPackage.GetDecompressedPackageStream(packageAsStream, true); //decompressedStream.WriteToFile(@"C:\users\dev\desktop\decompressed.pcc"); using var finalStream = MixinHandler.ApplyMixins(decompressedStream, file.Value, completedSingleApplicationCallback, failedApplicationCallback); CLog.Information(@"Compressing package to mod directory: " + file.Key, Settings.LogModMakerCompiler); finalStream.Position = 0; var package = MEPackageHandler.OpenMEPackage(finalStream); var outfile = Path.Combine(outdir, Path.GetFileName(file.Key)); package.save(outfile, false); // don't compress //finalStream.WriteToFile(outfile); //File.WriteAllBytes(outfile, finalStream.ToArray()); } catch (Exception e) { var mixinsStr = string.Join(@", ", file.Value.Select(x => x.PatchName)); Log.Error($@"Error in mixin application for file {file.Key}: {e.Message}"); failedApplicationCallback(M3L.GetString(M3L.string_interp_errorApplyingMixinsForFile, mixinsStr, file.Key, e.Message)); } } } else { //dlc var dlcPackage = VanillaDatabaseService.FetchVanillaSFAR(dlcFolderName); //do not have to open file multiple times. foreach (var file in mapping.Value) { try { using var packageAsStream = VanillaDatabaseService.FetchFileFromVanillaSFAR(dlcFolderName, file.Key, forcedDLC: dlcPackage); using var decompressedStream = MEPackage.GetDecompressedPackageStream(packageAsStream); using var finalStream = MixinHandler.ApplyMixins(decompressedStream, file.Value, completedSingleApplicationCallback, failedApplicationCallback); CLog.Information(@"Compressing package to mod directory: " + file.Key, Settings.LogModMakerCompiler); finalStream.Position = 0; var package = MEPackageHandler.OpenMEPackage(finalStream); var outfile = Path.Combine(outdir, Path.GetFileName(file.Key)); package.save(outfile, true); } catch (Exception e) { var mixinsStr = string.Join(@", ", file.Value.Select(x => x.PatchName)); Log.Error($@"Error in mixin application for file {file.Key}: {e.Message}"); failedApplicationCallback(M3L.GetString(M3L.string_interp_errorApplyingMixinsForFile, mixinsStr, file.Key, e.Message)); } //finalStream.WriteToFile(outfile); } } }); MixinHandler.FreeME3TweaksPatchData(); //Generate moddesc IniData ini = new IniData(); ini[@"ModManager"][@"cmmver"] = App.HighestSupportedModDesc.ToString(CultureInfo.InvariantCulture); //prevent commas ini[@"ModInfo"][@"game"] = @"ME3"; ini[@"ModInfo"][@"modname"] = modname; ini[@"ModInfo"][@"moddev"] = App.AppVersionHR; ini[@"ModInfo"][@"moddesc"] = M3L.GetString(M3L.string_compiledFromTheFollowingMixins); ini[@"ModInfo"][@"modver"] = @"1.0"; generateRepaceFilesMapping(ini, modpath); File.WriteAllText(Path.Combine(modpath, @"moddesc.ini"), ini.ToString()); }; nbw.RunWorkerCompleted += (a, b) => { OperationInProgress = false; ClearMixinHandler(); if (failedApplications.Count > 0) { var ld = new ListDialog(failedApplications, M3L.GetString(M3L.string_failedToApplyAllMixins), M3L.GetString(M3L.string_theFollowingMixinsFailedToApply), mainwindow); ld.ShowDialog(); } if (modpath != null) { OnClosing(new DataEventArgs(modpath)); } else { BottomLeftMessage = M3L.GetString(M3L.string_selectMixinsToCompile); } }; CompilePanelButton.IsOpen = false; nbw.RunWorkerAsync(); }
public static void ApplyMixinsToModule(KeyValuePair <ModJob.JobHeader, Dictionary <string, List <Mixin> > > mapping, string modpath, Action completedSingleApplicationCallback, Action <string> failedApplicationCallback) { var dlcFolderName = ModMakerCompiler.ModmakerChunkNameToDLCFoldername(mapping.Key.ToString()); var outdir = Path.Combine(modpath, ModMakerCompiler.HeaderToDefaultFoldername(mapping.Key), @"CookedPCConsole"); Directory.CreateDirectory(outdir); if (mapping.Key == ModJob.JobHeader.BASEGAME) { //basegame foreach (var file in mapping.Value) { try { using var packageAsStream = VanillaDatabaseService.FetchBasegameFile(MEGame.ME3, Path.GetFileName(file.Key)); //packageAsStream.WriteToFile(@"C:\users\dev\desktop\compressed.pcc"); using var decompressedStream = MEPackage.GetDecompressedPackageStream(packageAsStream, false, true); using var finalStream = MixinHandler.ApplyMixins(decompressedStream, file.Value, true, completedSingleApplicationCallback, failedApplicationCallback); CLog.Information(@"Compressing package to mod directory: " + file.Key, Settings.LogModMakerCompiler); finalStream.Position = 0; var package = MEPackageHandler.OpenMEPackageFromStream(finalStream); var outfile = Path.Combine(outdir, Path.GetFileName(file.Key)); package.Save(outfile, false, includeAdditionalPackagesToCook: false, includeDependencyTable: true); // don't compress, use mixin saving rules for basegame files } catch (Exception e) { var mixinsStr = string.Join(@", ", file.Value.Select(x => x.PatchName)); Log.Error($@"Error in mixin application for file {file.Key}: {e.Message}"); failedApplicationCallback(M3L.GetString(M3L.string_interp_errorApplyingMixinsForFile, mixinsStr, file.Key, e.Message)); } } } else { //dlc var dlcPackage = VanillaDatabaseService.FetchVanillaSFAR(dlcFolderName); //do not have to open file multiple times. foreach (var file in mapping.Value) { try { using var packageAsStream = VanillaDatabaseService.FetchFileFromVanillaSFAR(dlcFolderName, file.Key, forcedDLC: dlcPackage); //as file comes from backup, we don't need to decompress it, it will always be decompressed in sfar using var finalStream = MixinHandler.ApplyMixins(packageAsStream, file.Value, true, completedSingleApplicationCallback, failedApplicationCallback); var outfile = Path.Combine(outdir, Path.GetFileName(file.Key)); if (mapping.Key != ModJob.JobHeader.TESTPATCH) { // TestPatch is never unpacked. So there is not really point to // compressing it's rather small files. The other DLC jobs likely will be packed still, but this will save some disk space. CLog.Information($@"Compressing package to mod directory: {outfile}", Settings.LogModMakerCompiler); finalStream.Position = 0; var package = MEPackageHandler.OpenMEPackageFromStream(finalStream); package.Save(outfile, true); } else { Log.Information($@"Writing patched file to disk: {outfile}"); finalStream.WriteToFile(outfile); } } catch (Exception e) { var mixinsStr = string.Join(@", ", file.Value.Select(x => x.PatchName)); Log.Error($@"Error in mixin application for file {file.Key}: {e.Message}"); failedApplicationCallback(M3L.GetString(M3L.string_interp_errorApplyingMixinsForFile, mixinsStr, file.Key, e.Message)); } //finalStream.WriteToFile(outfile); } } }