public void PopulateDLCMods(bool includeDisabled, Func <InstalledDLCMod, bool> deleteConfirmationCallback = null, Action notifyDeleted = null, bool modNamePrefersTPMI = false) { var dlcDir = MEDirectories.DLCPath(this); var installedMods = MEDirectories.GetInstalledDLC(this, includeDisabled).Where(x => !MEDirectories.OfficialDLC(Game).Contains(x.TrimStart('x'), StringComparer.InvariantCultureIgnoreCase)); //Must run on UI thread Application.Current.Dispatcher.Invoke(delegate { UIInstalledDLCMods.ClearEx(); UIInstalledDLCMods.AddRange(installedMods.Select(x => new InstalledDLCMod(Path.Combine(dlcDir, x), Game, deleteConfirmationCallback, notifyDeleted, modNamePrefersTPMI)).ToList().OrderBy(x => x.ModName)); }); }
private void LoadME3FilesList() { var me3files = new List <BackupFile>(); var bup = BackupService.GetGameBackupPath(Mod.MEGame.ME3); if (bup != null) { var target = new GameTarget(Mod.MEGame.ME3, bup, false); var cookedPath = MEDirectories.CookedPath(target); foreach (var f in Extensions.GetFiles(cookedPath, @"\.pcc|\.tfc|\.afc|\.bin|\.tlk", SearchOption.AllDirectories)) { me3files.Add(new BackupFile(@"BASEGAME", Path.GetFileName(f))); } me3files.Sort(); //sort basegame var dlcDir = MEDirectories.DLCPath(target); var officialDLC = VanillaDatabaseService.GetInstalledOfficialDLC(target); foreach (var v in officialDLC) { var sfarPath = Path.Combine(dlcDir, v, @"CookedPCConsole", @"Default.sfar"); if (File.Exists(sfarPath)) { var filesToAdd = new List <BackupFile>(); DLCPackage dlc = new DLCPackage(sfarPath); foreach (var f in dlc.Files) { filesToAdd.Add(new BackupFile(v, Path.GetFileName(f.FileName))); } filesToAdd.Sort(); me3files.AddRange(filesToAdd); } } //TESTPATCH var tpPath = ME3Directory.GetTestPatchPath(target); if (File.Exists(tpPath)) { var filesToAdd = new List <BackupFile>(); DLCPackage dlc = new DLCPackage(tpPath); foreach (var f in dlc.Files) { filesToAdd.Add(new BackupFile(@"TESTPATCH", Path.GetFileName(f.FileName))); } filesToAdd.Sort(); me3files.AddRange(filesToAdd); } } Application.Current.Dispatcher.Invoke(delegate { ME3Files.ReplaceAll(me3files); }); Debug.WriteLine(@"Num ME3 files: " + ME3Files.Count); }
public DLCEntry(string name, List<string> files, MEDirectories.MEDirectories gameDirecs) { Name = name; if (files == null) return; foreach (string file in files) { GameFileEntry entry = new GameFileEntry(file, gameDirecs); Files.Add(entry); } }
/// <summary> /// Gets a list of allowable and not-allowable directories that can be installed to by this job. Disallowed always overrides allowed and if an item is not listed in allowed it is implicitly not allowed /// </summary> /// <param name="job"></param> /// <param name="game"></param> /// <returns></returns> public static SiloScopes GetScopedSilos(ModJob job, MEGame game) { switch (job.Header) { case JobHeader.LOCALIZATION: case JobHeader.ME1_CONFIG: case JobHeader.ME2_RCWMOD: case JobHeader.BALANCE_CHANGES: return(null); // There are no scopes for these headers. } SiloScopes scopes = new SiloScopes(); var dlcDir = MEDirectories.GetDLCPath(game, "") + Path.DirectorySeparatorChar; if (job.Header == JobHeader.BASEGAME) { // There are specific directories we allow installation to. if (game == MEGame.ME3) { scopes.DisallowedSilos.Add(@"Binaries\\Win32" + Path.DirectorySeparatorChar); //You are not allowed to install files into the game executable directory. ME1/2 unfortuantely share exec with exe dir. } scopes.AllowedSilos.Add(@"Binaries" + Path.DirectorySeparatorChar); //Exec files scopes.AllowedSilos.Add(@"BioGame" + Path.DirectorySeparatorChar); // Stuff in biogame scopes.AllowedSilos.Add(@"data" + Path.DirectorySeparatorChar); // Stuff in biogame scopes.DisallowedSilos.Add(dlcDir); // BASEGAME is not allowed into DLC scopes.AllowedSilos.Add(@"Engine" + Path.DirectorySeparatorChar); //Shaders } else if (GetHeadersToDLCNamesMap(game).TryGetValue(job.Header, out var dlcFoldername)) { // It's an official DLC var relativeDlcDir = Path.Combine(MEDirectories.GetDLCPath(game, ""), dlcFoldername) + Path.DirectorySeparatorChar; scopes.AllowedSilos.Add(relativeDlcDir); //Silos are folders. We should ensure they end with a slash } else if (job.Header == JobHeader.CUSTOMDLC) { // Have to get all resolved target folders. These are the scopes.AllowedSilos foreach (var cdlcn in job.CustomDLCFolderMapping.Values) { scopes.AllowedSilos.Add(Path.Combine(dlcDir, cdlcn) + Path.DirectorySeparatorChar); } // Get alternate dlc targets foreach (var adlc in job.AlternateDLCs.Where(x => x.Operation == AlternateDLC.AltDLCOperation.OP_ADD_CUSTOMDLC)) { scopes.AllowedSilos.Add(Path.Combine(dlcDir, adlc.DestinationDLCFolder) + Path.DirectorySeparatorChar); } } return(scopes); }
/// <summary> /// Populates list of 'extra' items for the game. This includes things like dlls, and for ME1, config files /// </summary> public void PopulateExtras() { var exeDir = MEDirectories.ExecutableDirectory(this); var dlls = Directory.GetFiles(exeDir, @"*.dll").Select(x => Path.GetFileName(x)); var expectedDlls = MEDirectories.VanillaDlls(this.Game); var extraDlls = dlls.Except(expectedDlls, StringComparer.InvariantCultureIgnoreCase); void notifyExtraFileDeleted(InstalledExtraFile ief) { ExtraFiles.Remove(ief); } ExtraFiles.ReplaceAll(extraDlls.Select(x => new InstalledExtraFile(Path.Combine(exeDir, x), InstalledExtraFile.EFileType.DLL, Game, notifyExtraFileDeleted))); }
public MixinManager() { MemoryAnalyzer.AddTrackedMemoryItem(@"Mixin Library Panel", new WeakReference(this)); DataContext = this; MixinHandler.LoadME3TweaksPackage(); AvailableOfficialMixins.ReplaceAll(MixinHandler.ME3TweaksPackageMixins.OrderBy(x => x.PatchName)); var backupPath = Utilities.GetGameBackupPath(Mod.MEGame.ME3); if (backupPath != null) { var dlcPath = MEDirectories.DLCPath(backupPath, Mod.MEGame.ME3); var headerTranslation = ModJob.GetHeadersToDLCNamesMap(Mod.MEGame.ME3); foreach (var mixin in AvailableOfficialMixins) { mixin.UIStatusChanging += MixinUIStatusChanging; if (mixin.TargetModule == ModJob.JobHeader.TESTPATCH) { string biogame = MEDirectories.BioGamePath(backupPath); var sfar = Path.Combine(biogame, @"Patches", @"PCConsole", @"Patch_001.sfar"); if (File.Exists(sfar)) { mixin.CanBeUsed = true; } } else if (mixin.TargetModule != ModJob.JobHeader.BASEGAME) { //DLC var resolvedPath = Path.Combine(dlcPath, headerTranslation[mixin.TargetModule]); if (Directory.Exists(resolvedPath)) { mixin.CanBeUsed = true; } } else { //BASEGAME mixin.CanBeUsed = true; } } } else { BottomLeftMessage = M3L.GetString(M3L.string_noGameBackupOfME3IsAvailableMixinsCannotBeUsedWithoutABackup); } ResetMixinsUIState(); LoadCommands(); InitializeComponent(); }
public static string GetExecutablePath(GameTarget target, bool preferRealGameExe = false) { if (target.Game == MEGame.ME2 && preferRealGameExe) { // Prefer ME2Game.exe if it exists var executableFolder = GetExecutableDirectory(target); var exeReal = Path.Combine(executableFolder, @"ME2Game.exe"); if (File.Exists(exeReal)) { return(exeReal); } } return(MEDirectories.GetExecutablePath(target.Game, target.TargetPath)); }
private void ToggleDLC() { try { var dlcFPath = MEDirectories.DLCPath(target); var currentDLCPath = Path.Combine(dlcFPath, DLCFolderName); string destPath = Path.Combine(dlcFPath, Enabled ? @"x" + UIDLCFolderName : UIDLCFolderName); Directory.Move(currentDLCPath, destPath); Enabled = !Enabled; DLCFolderName = Enabled ? UIDLCFolderName : @"x" + UIDLCFolderName; } catch (Exception e) { Log.Error($@"Error toggling DLC {DLCFolderName}: {e.Message}"); M3L.ShowDialog(Application.Current?.MainWindow, M3L.GetString(M3L.string_interp_errorTogglingDLC, e.Message), M3L.GetString(M3L.string_error), MessageBoxButton.OK, MessageBoxImage.Error); //this needs updated to be better } }
private void ToggleDLC() { try { var dlcFPath = MEDirectories.DLCPath(target); var currentDLCPath = Path.Combine(dlcFPath, DLCFolderName); string destPath = Path.Combine(dlcFPath, Enabled ? @"x" + UIDLCFolderName : UIDLCFolderName); Directory.Move(currentDLCPath, destPath); Enabled = !Enabled; DLCFolderName = Enabled ? UIDLCFolderName : @"x" + UIDLCFolderName; } catch (Exception e) { Log.Error($"Error toggling DLC {DLCFolderName}: {e.Message}"); Xceed.Wpf.Toolkit.MessageBox.Show("Error toggling DLC: " + e.Message); } }
/// <summary> /// Validates this mod can install against a game target with respect to the list of RequiredDLC. /// </summary> /// <param name="gameTarget">Target to validate against</param> /// <returns>List of missing DLC modules, or an empty list if none</returns> internal List <string> ValidateRequiredModulesAreInstalled(GameTarget gameTarget) { if (gameTarget.Game != Game) { throw new Exception("Cannot validate a mod against a gametarget that is not for its game"); } var requiredDLC = RequiredDLC.Select(x => { if (Enum.TryParse(x, out ModJob.JobHeader parsedHeader) && ModJob.GetHeadersToDLCNamesMap(Game).TryGetValue(parsedHeader, out var dlcname)) { return(dlcname); } return(x); }); var installedDLC = MEDirectories.GetInstalledDLC(gameTarget); return(requiredDLC.Except(installedDLC).ToList()); }
public static void TestAllImportsInMERFS() { var dlcModPath = Path.Combine(MEDirectories.GetDefaultGamePath(MERFileSystem.Game), "BioGame", "DLC", $"DLC_MOD_{MERFileSystem.Game}Randomizer", "CookedPC"); var packages = Directory.GetFiles(dlcModPath); var globalCache = MERFileSystem.GetGlobalCache(); //var globalP = Path.Combine(dlcModPath, "BioP_Global.pcc"); //if (File.Exists(globalP)) //{ // // This is used for animation lookups. // globalCache.InsertIntoCache(MEPackageHandler.OpenMEPackage(globalP)); //} foreach (var p in packages) { if (p.RepresentsPackageFilePath()) { MERPackageCache localCache = new MERPackageCache(); Debug.WriteLine($"Checking package file {p}"); var pack = MEPackageHandler.OpenMEPackage(p); foreach (var imp in pack.Imports) { if (imp.InstancedFullPath.StartsWith("Core.") || imp.InstancedFullPath.StartsWith("Engine.")) { continue; // These have some natives are always in same file. } if (imp.InstancedFullPath == "BioVFX_Z_TEXTURES.Generic.Glass_Shards_Norm" && MERFileSystem.Game == MEGame.ME2) { continue; // This is... native for some reason? } var resolvedExp = EntryImporter.ResolveImport(imp, globalCache, localCache); if (resolvedExp == null) { Debug.WriteLine($"Could not resolve import: {imp.InstancedFullPath}"); } } } } Debug.WriteLine("Done checking imports"); }
public void OnSelectedTargetChanged() { Supercedances.ClearEx(); if (SelectedTarget != null) { // maps DLC folder name -> mount number var mountpriorities = MEDirectories.GetMountPriorities(SelectedTarget); //maps filename to list of DLC in order of precedence var supercedances = MEDirectories.GetFileSupercedances(SelectedTarget).Where(x => x.Value.Count > 1).ToList(); foreach (var supercedance in supercedances) { SupercedanceList sl = new SupercedanceList() { Filename = supercedance.Key, WinningFile = new SupercedanceFile() { DLCName = supercedance.Value.First(), MountPriority = mountpriorities[supercedance.Value.First()], Game = SelectedTarget.Game }, Game = SelectedTarget.Game }; sl.LosingFiles.ReplaceAll(supercedance.Value.Skip(1).Take(supercedance.Value.Count - 1).Select(x => new SupercedanceFile() { DLCName = x, MountPriority = mountpriorities[x], Game = SelectedTarget.Game })); Supercedances.Add(sl); //var dlcname = supercedance.Value //SupercedanceFile winningFile = new SupercedanceFile() //{ // Fi // MountPriority = mountpriorities[], // DLCName = supercedance.Value.First() //}; } } Supercedances.Sort(x => x.Filename); }
private void LoadME2FilesList() { var me2files = new List <BackupFile>(); var bup = BackupService.GetGameBackupPath(Mod.MEGame.ME2); if (bup != null) { var target = new GameTarget(Mod.MEGame.ME2, bup, false); var cookedPath = MEDirectories.CookedPath(target); foreach (var f in Extensions.GetFiles(cookedPath, @"\.pcc|\.tfc|\.afc|\.bin|\.tlk", SearchOption.AllDirectories)) { me2files.Add(new BackupFile(@"BASEGAME", Path.GetFileName(f))); } me2files.Sort(); //sort basegame var dlcDir = MEDirectories.DLCPath(target); var officialDLC = VanillaDatabaseService.GetInstalledOfficialDLC(target); foreach (var v in officialDLC) { var cookedDLCPath = Path.Combine(dlcDir, v, @"CookedPC"); if (Directory.Exists(cookedDLCPath)) { var filesToAdd = new List <BackupFile>(); foreach (var f in Directory.EnumerateFiles(cookedDLCPath, @"*.pcc", SearchOption.TopDirectoryOnly)) { filesToAdd.Add(new BackupFile(v, Path.GetFileName(f))); } filesToAdd.Sort(); me2files.AddRange(filesToAdd); } } } Application.Current.Dispatcher.Invoke(delegate { ME2Files.ReplaceAll(me2files); }); Debug.WriteLine(@"Num ME2 files: " + ME2Files.Count); }
public static void GetExportsInPersistentThatAreAlsoInSub() { var dlcModPath = Path.Combine(MEDirectories.GetDefaultGamePath(MERFileSystem.Game), "BioGame", "DLC", $"DLC_MOD_{MERFileSystem.Game}Randomizer", "CookedPC"); var oldPersistentFile = MEPackageHandler.OpenMEPackage(Path.Combine(@"B:\SteamLibrary\steamapps\common\Mass Effect 2\BioGame\CookedPC", "BioP_JnkKgA.pcc")); var newPersistentFile = MEPackageHandler.OpenMEPackage(Path.Combine(dlcModPath, "BioP_JnkKgA.pcc")); var oldExpList = oldPersistentFile.Exports.Select(x => x.InstancedFullPath); var newExpList = newPersistentFile.Exports.Select(x => x.InstancedFullPath); var newExports = newExpList.Except(oldExpList).ToList(); var subFile = MEPackageHandler.OpenMEPackage(@"B:\SteamLibrary\steamapps\common\Mass Effect 2\BioGame\CookedPC\BioD_JnkKgA_300Labs.pcc"); var subExports = subFile.Exports.Select(x => x.InstancedFullPath); var sameExports = subExports.Intersect(newExports).ToList(); foreach (var v in sameExports) { Debug.WriteLine(v); } }
public List <InstalledASIMod> GetInstalledASIs() { List <InstalledASIMod> installedASIs = new List <InstalledASIMod>(); try { string asiDirectory = MEDirectories.ASIPath(this); if (asiDirectory != null && Directory.Exists(TargetPath)) { if (!Directory.Exists(asiDirectory)) { Directory.CreateDirectory(asiDirectory); //Create it, but we don't need it return(installedASIs); //It won't have anything in it if we are creating it } var asiFiles = Directory.GetFiles(asiDirectory, @"*.asi"); foreach (var asiFile in asiFiles) { var hash = Utilities.CalculateMD5(asiFile); var matchingManifestASI = ASIManager.GetASIVersionByHash(hash, Game); if (matchingManifestASI != null) { installedASIs.Add(new KnownInstalledASIMod(asiFile, hash, Game, matchingManifestASI)); } else { installedASIs.Add(new UnknownInstalledASIMod(asiFile, hash, Game)); } } } } catch (Exception e) { Log.Error(@"Error fetching list of installed ASIs: " + e.Message); } return(installedASIs); }
public static bool IsASILoaderInstalled(MEGame game) { if (!IsGameInstalled(game)) { return(false); } string dllDir = MEDirectories.GetExecutableFolderPath(game); string binkw23Path = Path.Combine(dllDir, "binkw23.dll"); string binkw32Path = Path.Combine(dllDir, "binkw32.dll"); const string me3binkw23MD5 = "128b560ef70e8085c507368da6f26fe6"; const string me3binkw32MD5 = "1acccbdae34e29ca7a50951999ed80d5"; const string me2binkw23MD5 = "56a99d682e752702604533b2d5055a5e"; const string me2binkw32MD5 = "a5318e756893f6232284202c1196da13"; const string me1binkw23MD5 = "d9e2a3b9303ca80560218af9f6eebaae"; const string me1binkw32MD5 = "30660f25ab7f7435b9f3e1a08422411a"; return(File.Exists(binkw23Path) && File.Exists(binkw32Path) && game switch { MEGame.ME1 => me1binkw23MD5, MEGame.ME2 => me2binkw23MD5, MEGame.ME3 => me3binkw23MD5, _ => throw new ArgumentOutOfRangeException(nameof(game), game, null) } == CalculateMD5(binkw23Path) &&
public static void TestPropertiesInMERFS() { var dlcModPath = Path.Combine(MEDirectories.GetDefaultGamePath(MERFileSystem.Game), "BioGame", "DLC", $"DLC_MOD_{MERFileSystem.Game}Randomizer", "CookedPC"); ReferenceCheckPackage rcp = new ReferenceCheckPackage(); bool checkCanceled = false; EntryChecker.CheckReferences(rcp, dlcModPath, EntryChecker.NonLocalizedStringConverter, x => Debug.WriteLine(x)); foreach (var s in rcp.GetInfoWarnings()) { Debug.WriteLine($"INFO: {s}"); } foreach (var s in rcp.GetSignificantIssues()) { Debug.WriteLine($"SIGNIFICANT: {s}"); } foreach (var s in rcp.GetBlockingErrors()) { Debug.WriteLine($"BLOCKING: {s}"); } }
/// <summary> /// Maps each DLC folder to it's MetaCMM file, if one exists. Otherwise it is mapped to null /// </summary> /// <param name="target"></param> /// <returns></returns> public static Dictionary <string, MetaCMM> GetMetaMappedInstalledDLC(GameTarget target, bool includeOfficial = true) { var installedDLC = GetInstalledDLC(target); var metamap = new Dictionary <string, MetaCMM>(); var dlcpath = GetDLCPath(target); foreach (var v in installedDLC) { if (!includeOfficial && MEDirectories.OfficialDLC(target.Game).Contains(v)) { continue; // This is not a mod } var meta = Path.Combine(dlcpath, v, @"_metacmm.txt"); MetaCMM mf = null; if (File.Exists(meta)) { mf = new MetaCMM(meta); } metamap[v] = mf; } return(metamap); }
/// <summary> /// Gets a list of installed ASI mods. /// </summary> /// <param name="game">Game to filter results by. Enter 1 2 or 3 for that game only, or anything else to get everything.</param> /// <returns></returns> private List <InstalledASIMod> getInstalledASIMods(Mod.MEGame game = Mod.MEGame.Unknown) { List <InstalledASIMod> results = new List <InstalledASIMod>(); if (SelectedTarget != null) { string asiDirectory = MEDirectories.ASIPath(SelectedTarget); string gameDirectory = ME1Directory.gamePath; if (asiDirectory != null && Directory.Exists(gameDirectory)) { if (!Directory.Exists(asiDirectory)) { Directory.CreateDirectory(asiDirectory); return(results); //It won't have anything in it if we are creating it } var asiFiles = Directory.GetFiles(asiDirectory, @"*.asi"); foreach (var asiFile in asiFiles) { results.Add(new InstalledASIMod(asiFile, game)); } } } return(results); }
private void BeginBackup() { if (Utilities.IsGameRunning(BackupSourceTarget.Game)) { M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_cannotBackupGameWhileRunning, Utilities.GetGameName(BackupSourceTarget.Game)), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error); return; } NamedBackgroundWorker bw = new NamedBackgroundWorker(Game.ToString() + @"Backup"); bw.DoWork += (a, b) => { BackupInProgress = true; List <string> nonVanillaFiles = new List <string>(); void nonVanillaFileFoundCallback(string filepath) { Log.Error($@"Non-vanilla file found: {filepath}"); nonVanillaFiles.Add(filepath); } List <string> inconsistentDLC = new List <string>(); void inconsistentDLCFoundCallback(string filepath) { if (BackupSourceTarget.Supported) { Log.Error($@"DLC is in an inconsistent state: {filepath}"); inconsistentDLC.Add(filepath); } else { Log.Error(@"Detected an inconsistent DLC, likely due to an unofficial copy of the game"); } } ProgressVisible = true; ProgressIndeterminate = true; BackupStatus = M3L.GetString(M3L.string_validatingBackupSource); VanillaDatabaseService.LoadDatabaseFor(Game); bool isVanilla = VanillaDatabaseService.ValidateTargetAgainstVanilla(BackupSourceTarget, nonVanillaFileFoundCallback); bool isDLCConsistent = VanillaDatabaseService.ValidateTargetDLCConsistency(BackupSourceTarget, inconsistentDLCCallback: inconsistentDLCFoundCallback); List <string> dlcModsInstalled = VanillaDatabaseService.GetInstalledDLCMods(BackupSourceTarget); if (isVanilla && isDLCConsistent && dlcModsInstalled.Count == 0) { BackupStatus = M3L.GetString(M3L.string_waitingForUserInput); string backupPath = null; bool end = false; Application.Current.Dispatcher.Invoke(delegate { Log.Error(@"Prompting user to select backup destination"); CommonOpenFileDialog m = new CommonOpenFileDialog { IsFolderPicker = true, EnsurePathExists = true, Title = M3L.GetString(M3L.string_selectBackupDestination) }; if (m.ShowDialog() == CommonFileDialogResult.Ok) { //Check empty backupPath = m.FileName; if (Directory.Exists(backupPath)) { if (Directory.GetFiles(backupPath).Length > 0 || Directory.GetDirectories(backupPath).Length > 0) { //Directory not empty Log.Error(@"Selected backup directory is not empty."); M3L.ShowDialog(window, M3L.GetString(M3L.string_directoryIsNotEmptyMustBeEmpty), M3L.GetString(M3L.string_directoryNotEmpty), MessageBoxButton.OK, MessageBoxImage.Error); end = true; EndBackup(); return; } } } else { end = true; EndBackup(); return; } }); if (end) { return; } #region callbacks void fileCopiedCallback() { ProgressValue++; } string dlcFolderpath = MEDirectories.DLCPath(BackupSourceTarget) + '\\'; int dlcSubStringLen = dlcFolderpath.Length; bool aboutToCopyCallback(string file) { if (file.Contains(@"\cmmbackup\")) { return(false); //do not copy cmmbackup files } if (file.StartsWith(dlcFolderpath)) { //It's a DLC! string dlcname = file.Substring(dlcSubStringLen); dlcname = dlcname.Substring(0, dlcname.IndexOf('\\')); if (MEDirectories.OfficialDLCNames(BackupSourceTarget.Game).TryGetValue(dlcname, out var hrName)) { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, hrName); } else { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, dlcname); } } else { //It's basegame if (file.EndsWith(@".bik")) { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.string_movies); } else if (new FileInfo(file).Length > 52428800) { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, Path.GetFileName(file)); } else { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.string_basegame); } } return(true); } void totalFilesToCopyCallback(int total) { ProgressValue = 0; ProgressIndeterminate = false; ProgressMax = total; } #endregion BackupStatus = M3L.GetString(M3L.string_creatingBackup); CopyDir.CopyAll_ProgressBar(new DirectoryInfo(BackupSourceTarget.TargetPath), new DirectoryInfo(backupPath), totalItemsToCopyCallback: totalFilesToCopyCallback, aboutToCopyCallback: aboutToCopyCallback, fileCopiedCallback: fileCopiedCallback, ignoredExtensions: new[] { @"*.pdf", @"*.mp3" }); switch (Game) { case Mod.MEGame.ME1: case Mod.MEGame.ME2: Utilities.WriteRegistryKey(App.BACKUP_REGISTRY_KEY, Game + @"VanillaBackupLocation", backupPath); break; case Mod.MEGame.ME3: Utilities.WriteRegistryKey(App.REGISTRY_KEY_ME3CMM, @"VanillaCopyLocation", backupPath); break; } Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Success" } }); EndBackup(); return; } if (!isVanilla) { //Show UI for non vanilla Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Failure, Game modified" } }); b.Result = (nonVanillaFiles, M3L.GetString(M3L.string_cannotBackupModifiedGame), M3L.GetString(M3L.string_followingFilesDoNotMatchTheVanillaDatabase)); } else if (!isDLCConsistent) { Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Failure, DLC inconsistent" } }); if (BackupSourceTarget.Supported) { b.Result = (inconsistentDLC, M3L.GetString(M3L.string_inconsistentDLCDetected), M3L.GetString(M3L.string_dialogTheFollowingDLCAreInAnInconsistentState)); } else { b.Result = (M3L.GetString(M3L.string_inconsistentDLCDetected), M3L.GetString(M3L.string_inconsistentDLCDetectedUnofficialGame)); } } else if (dlcModsInstalled.Count > 0) { Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Failure, DLC mods found" } }); b.Result = (dlcModsInstalled, M3L.GetString(M3L.string_dlcModsAreInstalled), M3L.GetString(M3L.string_dialogDLCModsWereDetectedCannotBackup)); } EndBackup(); }; bw.RunWorkerCompleted += (a, b) => { if (b.Result is (List <string> listItems, string title, string text)) { ListDialog ld = new ListDialog(listItems, title, text, window); ld.Show(); } else if (b.Result is (string errortitle, string message)) { M3L.ShowDialog(window, message, errortitle, MessageBoxButton.OK, MessageBoxImage.Error); } CommandManager.InvalidateRequerySuggested(); }; bw.RunWorkerAsync(); }
// Todo: ME3Exp 5.1: Get rid of this and use the import resolver. It must support a cache so we don't constnatly open packages internal static ExportEntry FindExternalAsset(ImportEntry entry, List <ExportEntry> alreadyLoadedPackageEntries, List <IMEPackage> openedPackages) { //Debug.WriteLine("Finding external asset " + entry.GetFullPath); if (entry.Game == MEGame.ME1) { var sourcePackageInternalPath = entry.FullPath.Substring(entry.FullPath.IndexOf('.') + 1); string baseName = entry.FileRef.FollowLink(entry.idxLink).Split('.')[0].ToUpper() + ".upk"; //Get package filename var preloadedPackageEntry = alreadyLoadedPackageEntries?.FirstOrDefault(x => Path.GetFileName(x.FileRef.FilePath).Equals(baseName, StringComparison.InvariantCultureIgnoreCase)); if (preloadedPackageEntry == null && MELoadedFiles.GetFilesLoadedInGame(MEGame.ME1).TryGetValue(baseName, out string packagePath)) { var package = MEPackageHandler.OpenMEPackage(packagePath); if (openedPackages != null && !openedPackages.Contains(package)) { openedPackages.Add(package); } var foundExp = package.Exports.FirstOrDefault(exp => exp.FullPath == sourcePackageInternalPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } if (openedPackages == null) { package.Dispose(); } } else { Debug.WriteLine("ME1 External Asset lookup: Using existing preloaded export package"); var foundExp = preloadedPackageEntry.FileRef.Exports.FirstOrDefault(exp => exp.FullPath == sourcePackageInternalPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } } } else { // Next, split the filename by underscores string filenameWithoutExtension = Path.GetFileNameWithoutExtension(entry.FileRef.FilePath).ToLower(); string containingDirectory = Path.GetDirectoryName(entry.FileRef.FilePath); var packagesToCheck = new List <string>(); var gameFiles = MELoadedFiles.GetFilesLoadedInGame(entry.Game); if (filenameWithoutExtension.StartsWith("bioa_") || filenameWithoutExtension.StartsWith("biod_")) { string[] parts = filenameWithoutExtension.Split('_'); if (parts.Length >= 2) //BioA_Nor_WowThatsAlot310.pcc { string bioad = $"{parts[0]}_{parts[1]}.pcc"; string filename = Path.Combine(containingDirectory, bioad); //BioA_Nor.pcc if (File.Exists(filename)) { packagesToCheck.Add(filename); } else { if (gameFiles.TryGetValue(filename, out string inGamePath)) { packagesToCheck.Add(inGamePath); } } string biop = $"BioP_{parts[1]}.pcc"; filename = Path.Combine(containingDirectory, biop); //BioP_Nor.pcc if (File.Exists(filename)) { packagesToCheck.Add(filename); } else { if (gameFiles.TryGetValue(filename, out string inGamePath)) { packagesToCheck.Add(inGamePath); } } } } // Add globals packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "SFXGame.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "EntryMenu.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), entry.Game == MEGame.ME3 ? "Startup.pcc" : "Startup_INT.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "Engine.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "Engine.u")); //ME1 foreach (string packagePath in packagesToCheck) { if (File.Exists(packagePath)) { var preloadedPackageEntry = alreadyLoadedPackageEntries?.FirstOrDefault(x => Path.GetFileName(x.FileRef.FilePath).Equals(packagePath, StringComparison.InvariantCultureIgnoreCase)); if (preloadedPackageEntry == null) { var sentry = searchPackageForEntry(packagePath, entry.FullPath, entry.ClassName, openedPackages); if (sentry != null) { return(sentry); } } else { Debug.WriteLine("ME2/3 External Asset lookup: Using existing preloaded export package"); var foundExp = preloadedPackageEntry.FileRef.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } } } } } Debug.WriteLine("Could not find external asset: " + entry.FullPath); return(null); }
private void StartGuiCompatibilityScanner() { NamedBackgroundWorker bw = new NamedBackgroundWorker(@"GUICompatibilityScanner"); bw.DoWork += (a, b) => { Percent = 0; ActionString = M3L.GetString(M3L.string_preparingCompatGenerator); ActionSubstring = M3L.GetString(M3L.string_pleaseWait); var installedDLCMods = VanillaDatabaseService.GetInstalledDLCMods(target); var numTotalDLCMods = installedDLCMods.Count; var uiModInstalled = installedDLCMods.Intersect(DLCUIModFolderNames).Any(); var dlcRoot = MEDirectories.DLCPath(target); if (uiModInstalled) { var nonUIinstalledDLCMods = installedDLCMods.Except(DLCUIModFolderNamesIncludingPatch).ToList(); if (nonUIinstalledDLCMods.Count < numTotalDLCMods && nonUIinstalledDLCMods.Count > 0) { //Get UI library bool xbxLibrary = installedDLCMods.Contains(@"DLC_CON_XBX"); bool uiscalinglibrary = installedDLCMods.Contains(@"DLC_CON_UIScaling"); if (!xbxLibrary && !uiscalinglibrary) { uiscalinglibrary = installedDLCMods.Contains(@"DLC_CON_UIScaling_Shared"); } if (xbxLibrary && uiscalinglibrary) { //can't have both! Not supported. Application.Current.Dispatcher.Invoke(delegate { Log.Error(@"Cannot make compat pack: Both ISM and SP Controller are installed, this is not supported."); M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogCannotGenerateCompatPackInvalidConfig), M3L.GetString(M3L.string_invalidConfiguration), MessageBoxButton.OK, MessageBoxImage.Error); OnClosing(DataEventArgs.Empty); }); b.Result = GUICompatibilityThreadResult.INVALID_UI_MOD_CONFIG; return; } void progressCallback(long done, long total) { ActionString = M3L.GetString(M3L.string_downloadingUiLibrary); ActionSubstring = xbxLibrary ? @"DLC_CON_XBX" : @"DLC_CON_UIScaling"; Percent = getPercent(done, total); } var uiLibraryPath = GetUILibraryPath(xbxLibrary ? @"DLC_CON_XBX" : @"DLC_CON_UIScaling", true, progressCallback); if (uiLibraryPath == null) { Log.Error(@"Required UI library could not be downloaded."); Application.Current.Dispatcher.Invoke(delegate { M3L.ShowDialog(window, M3L.GetString(M3L.string_cannotGeneratorCompatPackCouldNotDownload), M3L.GetString(M3L.string_couldNotAcquireUiLibrary), MessageBoxButton.OK, MessageBoxImage.Error); OnClosing(DataEventArgs.Empty); }); b.Result = GUICompatibilityThreadResult.NO_UI_LIBRARY; return; } //Open UI library SevenZipExtractor libraryArchive = new SevenZipExtractor(uiLibraryPath); List <string> libraryGUIs = libraryArchive.ArchiveFileData.Where(x => !x.IsDirectory).Select(x => x.FileName.Substring(Path.GetFileNameWithoutExtension(uiLibraryPath).Length + 1)).Select(x => x.Substring(0, x.Length - 4)).ToList(); //remove / on end too //We have UI mod(s) installed and at least one other DLC mod. var supercedanceList = getFileSupercedances().Where(x => x.Value.Any(x => !DLCUIModFolderNamesIncludingPatch.Contains(x))).ToDictionary(p => p.Key, p => p.Value); //Find GUIs ConcurrentDictionary <string, string> filesToBePatched = new ConcurrentDictionary <string, string>(); //Dictionary because there is no ConcurrentList. Keys and values are idenitcal. ActionString = M3L.GetString(M3L.string_scanningForGuiExports); ActionSubstring = M3L.GetString(M3L.string_pleaseWait); Percent = 0; int done = 0; string singlesuffix = M3L.GetString(M3L.string_singularFile); string pluralsuffix = M3L.GetString(M3L.string_pluralFiles); Parallel.ForEach(supercedanceList, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, (pair) => { var firstNonUIModDlc = pair.Value.FirstOrDefault(x => !DLCUIModFolderNamesIncludingPatch.Contains(x)); if (firstNonUIModDlc != null) { //Scan file. var packagefile = Path.Combine(dlcRoot, firstNonUIModDlc, target.Game == MEGame.ME3 ? @"CookedPCConsole" : @"CookedPC", pair.Key); Log.Information(@"Scanning file for GFXMovieInfo exports: " + packagefile); if (!File.Exists(packagefile)) { throw new Exception($@"Package file for inspecting GUIs in was not found: {packagefile}"); } var package = MEPackageHandler.OpenMEPackage(packagefile); var guiExports = package.Exports.Where(x => !x.IsDefaultObject && x.ClassName == @"GFxMovieInfo").ToList(); if (guiExports.Count > 0) { //potential item needing replacement //Check GUI library to see if we have anything. foreach (var export in guiExports) { if (libraryGUIs.Contains(export.GetFullPath, StringComparer.InvariantCultureIgnoreCase)) { //match filesToBePatched[packagefile] = packagefile; ActionSubstring = M3L.GetString(M3L.string_interp_XFilesNeedToBePatched, filesToBePatched.Count.ToString(), filesToBePatched.Count == 1 ? singlesuffix : pluralsuffix); Log.Information($@"{firstNonUIModDlc} {pair.Key} has GUI export that is in UI library, marking for patching. Trigger: {export.GetFullPath}"); break; } } } } Interlocked.Increment(ref done); Percent = getPercent(done, supercedanceList.Count); }); if (filesToBePatched.Count > 0) { Log.Information(@"A GUI compatibility patch is required for this game configuration"); b.Result = GUICompatibilityThreadResult.REQUIRED; var generatedMod = GenerateCompatibilityPackForFiles(nonUIinstalledDLCMods, filesToBePatched.Keys.ToList(), libraryArchive); b.Result = GUICompatibilityThreadResult.GENERATED_PACK; Application.Current.Dispatcher.Invoke(delegate { ((MainWindow)window).LoadMods(generatedMod); }); //reload to this mod } } Log.Information(@"A GUI compatibility patch is not required for this game configuration"); b.Result = GUICompatibilityThreadResult.NOT_REQUIRED; } else { Log.Information(@"No UI mods are installed - no GUI compatibility pack required"); b.Result = GUICompatibilityThreadResult.NO_UI_MODS_INSTALLED; } }; bw.RunWorkerCompleted += (a, b) => { if (b.Result is GUICompatibilityThreadResult gctr) { Analytics.TrackEvent(@"Generated a UI compatibility pack", new Dictionary <string, string>() { { @"Result", gctr.ToString() } }); OnClosing(DataEventArgs.Empty); } else { throw new Exception(@"GUI Compatibility generator thread did not return a result! Please report this to ME3Tweaks"); } }; bw.RunWorkerAsync(); }
public static bool RunTOCOnGameTarget(GameTarget target, Action <int> percentDoneCallback = null) { Log.Information(@"Autotocing game: " + target.TargetPath); //get toc target folders, ensuring we clean up the inputs a bit. string baseDir = Path.GetFullPath(Path.Combine(target.TargetPath, @"BIOGame")); string dlcDirRoot = MEDirectories.DLCPath(target); if (!Directory.Exists(dlcDirRoot)) { Log.Error(@"Specified game directory does not appear to be a Mass Effect 3 root game directory (DLC folder missing)."); return(false); } var tocTargets = (new DirectoryInfo(dlcDirRoot)).GetDirectories().Select(x => x.FullName).Where(x => Path.GetFileName(x).StartsWith(@"DLC_", StringComparison.OrdinalIgnoreCase)).ToList(); tocTargets.Add(baseDir); tocTargets.Add(Path.Combine(target.TargetPath, @"BIOGame\Patches\PCConsole\Patch_001.sfar")); //Debug.WriteLine("Found TOC Targets:"); tocTargets.ForEach(x => Debug.WriteLine(x)); //Debug.WriteLine("=====Generating TOC Files====="); int done = 0; foreach (var tocTarget in tocTargets) { string sfar = Path.Combine(tocTarget, SFAR_SUBPATH); if (tocTarget.EndsWith(@".sfar")) { //TestPatch var watch = Stopwatch.StartNew(); DLCPackage dlc = new DLCPackage(tocTarget); var tocResult = dlc.UpdateTOCbin(); watch.Stop(); if (tocResult == DLCPackage.DLCTOCUpdateResult.RESULT_UPDATE_NOT_NECESSARY) { Log.Information($@"TOC is already up to date in {tocTarget}"); } else if (tocResult == DLCPackage.DLCTOCUpdateResult.RESULT_UPDATED) { var elapsedMs = watch.ElapsedMilliseconds; Log.Information($@"{tocTarget} - Ran SFAR TOC, took {elapsedMs}ms"); } } else if (ME3Directory.OfficialDLCNames.ContainsKey(Path.GetFileName(tocTarget))) { //Official DLC if (File.Exists(sfar)) { if (new FileInfo(sfar).Length == 32) //DLC is unpacked for sure { CreateUnpackedTOC(tocTarget); } else { //AutoTOC it - SFAR is not unpacked var watch = System.Diagnostics.Stopwatch.StartNew(); DLCPackage dlc = new DLCPackage(sfar); var tocResult = dlc.UpdateTOCbin(); watch.Stop(); if (tocResult == DLCPackage.DLCTOCUpdateResult.RESULT_ERROR_NO_ENTRIES) { Log.Information($@"No DLC entries in SFAR... Suspicious. Creating empty TOC for {tocTarget}"); CreateUnpackedTOC(tocTarget); } else if (tocResult == DLCPackage.DLCTOCUpdateResult.RESULT_UPDATE_NOT_NECESSARY) { Log.Information($@"TOC is already up to date in {tocTarget}"); } else if (tocResult == DLCPackage.DLCTOCUpdateResult.RESULT_UPDATED) { var elapsedMs = watch.ElapsedMilliseconds; Log.Information($@"{Path.GetFileName(tocTarget)} - Ran SFAR TOC, took {elapsedMs}ms"); } } } } else { //TOC it unpacked style // Console.WriteLine(foldername + ", - UNPACKED TOC"); CreateUnpackedTOC(tocTarget); } done++; percentDoneCallback?.Invoke((int)Math.Floor(done * 100.0 / tocTargets.Count)); } return(true); }
private void BeginBackup() { var targetToBackup = BackupSourceTarget; if (!targetToBackup.IsCustomOption) { if (Utilities.IsGameRunning(targetToBackup.Game)) { M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_cannotBackupGameWhileRunning, Utilities.GetGameName(BackupSourceTarget.Game)), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error); return; } } else { // Point to existing game installation Log.Information(@"BeginBackup() with IsCustomOption."); var linkWarning = M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_linkTargetWontBeModdable), M3L.GetString(M3L.string_linkWarning), MessageBoxButton.OKCancel, MessageBoxImage.Warning); if (linkWarning == MessageBoxResult.Cancel) { Log.Information(@"User aborted linking due to dialog"); return; } Log.Information(@"Prompting user to select executable of link target"); var gameexe = Utilities.PromptForGameExecutable(new[] { Game }); if (gameexe == null) { return; } targetToBackup = new GameTarget(Game, Utilities.GetGamePathFromExe(Game, gameexe), false, true); if (AvailableBackupSources.Any(x => x.TargetPath.Equals(targetToBackup.TargetPath, StringComparison.InvariantCultureIgnoreCase))) { // Can't point to an existing modding target Log.Error(@"This target is not valid to point to as a backup: It is listed a modding target already, it must be removed as a target first"); M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_dialog_linkFailedAlreadyATarget), M3L.GetString(M3L.string_cannotLinkGameCopy), MessageBoxButton.OK, MessageBoxImage.Error); return; } var validationFailureReason = targetToBackup.ValidateTarget(ignoreCmmVanilla: true); if (!targetToBackup.IsValid) { Log.Error(@"This installation is not valid to point to as a backup: " + validationFailureReason); M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_dialog_linkFailedInvalidTarget, validationFailureReason), M3L.GetString(M3L.string_invalidGameCopy), MessageBoxButton.OK, MessageBoxImage.Error); return; } } NamedBackgroundWorker nbw = new NamedBackgroundWorker(Game + @"Backup"); nbw.WorkerReportsProgress = true; nbw.ProgressChanged += (a, b) => { if (b.UserState is double d) { window.TaskBarItemInfoHandler.ProgressValue = d; } else if (b.UserState is TaskbarItemProgressState tbs) { window.TaskBarItemInfoHandler.ProgressState = tbs; } }; nbw.DoWork += (a, b) => { Log.Information(@"Starting the backup thread. Checking path: " + targetToBackup.TargetPath); BackupInProgress = true; bool end = false; List <string> nonVanillaFiles = new List <string>(); void nonVanillaFileFoundCallback(string filepath) { Log.Error($@"Non-vanilla file found: {filepath}"); nonVanillaFiles.Add(filepath); } List <string> inconsistentDLC = new List <string>(); void inconsistentDLCFoundCallback(string filepath) { if (targetToBackup.Supported) { Log.Error($@"DLC is in an inconsistent state: {filepath}"); inconsistentDLC.Add(filepath); } else { Log.Error(@"Detected an inconsistent DLC, likely due to an unofficial copy of the game"); } } ProgressVisible = true; ProgressIndeterminate = true; BackupStatus = M3L.GetString(M3L.string_validatingBackupSource); Log.Information(@"Checking target is vanilla"); bool isVanilla = VanillaDatabaseService.ValidateTargetAgainstVanilla(targetToBackup, nonVanillaFileFoundCallback); Log.Information(@"Checking DLC consistency"); bool isDLCConsistent = VanillaDatabaseService.ValidateTargetDLCConsistency(targetToBackup, inconsistentDLCCallback: inconsistentDLCFoundCallback); Log.Information(@"Checking only vanilla DLC is installed"); List <string> dlcModsInstalled = VanillaDatabaseService.GetInstalledDLCMods(targetToBackup).Select(x => { var tpmi = ThirdPartyServices.GetThirdPartyModInfo(x, targetToBackup.Game); if (tpmi != null) { return($@"{x} ({tpmi.modname})"); } return(x); }).ToList(); List <string> installedDLC = VanillaDatabaseService.GetInstalledOfficialDLC(targetToBackup); List <string> allOfficialDLC = MEDirectories.OfficialDLC(targetToBackup.Game); if (installedDLC.Count() < allOfficialDLC.Count()) { var dlcList = string.Join("\n - ", allOfficialDLC.Except(installedDLC).Select(x => $@"{MEDirectories.OfficialDLCNames(targetToBackup.Game)[x]} ({x})")); //do not localize dlcList = @" - " + dlcList; Log.Information(@"The following dlc will be missing in the backup if user continues: " + dlcList); Application.Current.Dispatcher.Invoke(delegate { var cancelDueToNotAllDLC = M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_notAllDLCInstalled, dlcList), M3L.GetString(M3L.string_someDlcNotInstalled), MessageBoxButton.YesNo, MessageBoxImage.Warning); if (cancelDueToNotAllDLC == MessageBoxResult.No) { end = true; EndBackup(); return; } }); } if (end) { return; } if (isVanilla && isDLCConsistent && dlcModsInstalled.Count == 0) { BackupStatus = M3L.GetString(M3L.string_waitingForUserInput); string backupPath = null; if (!targetToBackup.IsCustomOption) { // Creating a new backup nbw.ReportProgress(0, TaskDialogProgressBarState.Paused); Application.Current.Dispatcher.Invoke(delegate { Log.Information(@"Prompting user to select backup destination"); CommonOpenFileDialog m = new CommonOpenFileDialog { IsFolderPicker = true, EnsurePathExists = true, Title = M3L.GetString(M3L.string_selectBackupDestination) }; if (m.ShowDialog() == CommonFileDialogResult.Ok) { backupPath = m.FileName; Log.Information(@"Backup path chosen: " + backupPath); bool okToBackup = validateBackupPath(backupPath, targetToBackup); if (!okToBackup) { end = true; EndBackup(); return; } } else { end = true; EndBackup(); return; } }); if (end) { return; } nbw.ReportProgress(0, TaskbarItemProgressState.Indeterminate); } else { Log.Information(@"Linking existing backup at " + targetToBackup.TargetPath); backupPath = targetToBackup.TargetPath; // Linking existing backup Application.Current.Dispatcher.Invoke(delegate { bool okToBackup = validateBackupPath(targetToBackup.TargetPath, targetToBackup); if (!okToBackup) { end = true; EndBackup(); return; } }); } if (end) { return; } if (!targetToBackup.IsCustomOption) { #region callbacks and copy code // Copy to new backup void fileCopiedCallback() { ProgressValue++; if (ProgressMax > 0) { nbw.ReportProgress(0, ProgressValue * 1.0 / ProgressMax); } } string dlcFolderpath = MEDirectories.DLCPath(targetToBackup) + '\\'; int dlcSubStringLen = dlcFolderpath.Length; bool aboutToCopyCallback(string file) { try { if (file.Contains(@"\cmmbackup\")) { return(false); //do not copy cmmbackup files } if (file.StartsWith(dlcFolderpath, StringComparison.InvariantCultureIgnoreCase)) { //It's a DLC! string dlcname = file.Substring(dlcSubStringLen); var dlcFolderNameEndPos = dlcname.IndexOf('\\'); if (dlcFolderNameEndPos > 0) { dlcname = dlcname.Substring(0, dlcFolderNameEndPos); if (MEDirectories.OfficialDLCNames(targetToBackup.Game) .TryGetValue(dlcname, out var hrName)) { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, hrName); } else { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, dlcname); } } else { // Loose files in the DLC folder BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.GetString(M3L.string_basegame)); } } else { //It's basegame if (file.EndsWith(@".bik")) { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.GetString(M3L.string_movies)); } else if (new FileInfo(file).Length > 52428800) { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, Path.GetFileName(file)); } else { BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.GetString(M3L.string_basegame)); } } } catch (Exception e) { Crashes.TrackError(e, new Dictionary <string, string>() { { @"dlcFolderpath", dlcFolderpath }, { @"dlcSubStringLen", dlcSubStringLen.ToString() }, { @"file", file } }); } return(true); } void totalFilesToCopyCallback(int total) { ProgressValue = 0; ProgressIndeterminate = false; ProgressMax = total; nbw.ReportProgress(0, TaskbarItemProgressState.Normal); } BackupStatus = M3L.GetString(M3L.string_creatingBackup); Log.Information($@"Backing up {targetToBackup.TargetPath} to {backupPath}"); nbw.ReportProgress(0, TaskbarItemProgressState.Normal); CopyDir.CopyAll_ProgressBar(new DirectoryInfo(targetToBackup.TargetPath), new DirectoryInfo(backupPath), totalItemsToCopyCallback: totalFilesToCopyCallback, aboutToCopyCallback: aboutToCopyCallback, fileCopiedCallback: fileCopiedCallback, ignoredExtensions: new[] { @"*.pdf", @"*.mp3" }); #endregion } // Write key switch (Game) { case Mod.MEGame.ME1: case Mod.MEGame.ME2: Utilities.WriteRegistryKey(App.BACKUP_REGISTRY_KEY, Game + @"VanillaBackupLocation", backupPath); break; case Mod.MEGame.ME3: Utilities.WriteRegistryKey(App.REGISTRY_KEY_ME3CMM, @"VanillaCopyLocation", backupPath); break; } var cmmvanilla = Path.Combine(backupPath, @"cmm_vanilla"); if (!File.Exists(cmmvanilla)) { Log.Information($@"Writing cmm_vanilla to " + cmmvanilla); File.Create(cmmvanilla).Close(); } Log.Information($@"Backup completed."); Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Success" }, { @"Type", targetToBackup.IsCustomOption ? @"Linked" : @"Copy" } }); EndBackup(); return; } if (!isVanilla) { //Show UI for non vanilla Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Failure, Game modified" } }); b.Result = (nonVanillaFiles, M3L.GetString(M3L.string_cannotBackupModifiedGame), M3L.GetString(M3L.string_followingFilesDoNotMatchTheVanillaDatabase)); } else if (!isDLCConsistent) { Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Failure, DLC inconsistent" } }); if (targetToBackup.Supported) { b.Result = (inconsistentDLC, M3L.GetString(M3L.string_inconsistentDLCDetected), M3L.GetString(M3L.string_dialogTheFollowingDLCAreInAnInconsistentState)); } else { b.Result = (M3L.GetString(M3L.string_inconsistentDLCDetected), M3L.GetString(M3L.string_inconsistentDLCDetectedUnofficialGame)); } } else if (dlcModsInstalled.Count > 0) { Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>() { { @"Game", Game.ToString() }, { @"Result", @"Failure, DLC mods found" } }); b.Result = (dlcModsInstalled, M3L.GetString(M3L.string_dlcModsAreInstalled), M3L.GetString(M3L.string_dialogDLCModsWereDetectedCannotBackup)); } EndBackup(); }; nbw.RunWorkerCompleted += (a, b) => { if (b.Error != null) { Log.Error($@"Exception occured in {nbw.Name} thread: {b.Error.Message}"); } window.TaskBarItemInfoHandler.ProgressState = TaskbarItemProgressState.None; if (b.Result is (List <string> listItems, string title, string text)) { ListDialog ld = new ListDialog(listItems, title, text, window); ld.Show(); } else if (b.Result is (string errortitle, string message)) { M3L.ShowDialog(window, message, errortitle, MessageBoxButton.OK, MessageBoxImage.Error); } CommandManager.InvalidateRequerySuggested(); }; nbw.RunWorkerAsync(); }
public GameFileEntry(string path, MEDirectories.MEDirectories gameDirecs) : base() { Name = path.Remove(0, gameDirecs.BasePathLength); FilePath = path; }
public static IEntry EnsureClassIsInFile(IMEPackage pcc, string className) { //check to see class is already in file foreach (ImportEntry import in pcc.Imports) { if (import.IsClass && import.ObjectName == className) { return(import); } } foreach (ExportEntry export in pcc.Exports) { if (export.IsClass && export.ObjectName == className) { return(export); } } ClassInfo info = UnrealObjectInfo.GetClassOrStructInfo(pcc.Game, className); //backup some package state so we can undo changes if something goes wrong int exportCount = pcc.ExportCount; int importCount = pcc.ImportCount; List <string> nameListBackup = pcc.Names.ToList(); try { if (EntryImporter.IsSafeToImportFrom(info.pccPath, pcc.Game)) { string package = Path.GetFileNameWithoutExtension(info.pccPath); return(pcc.getEntryOrAddImport($"{package}.{className}")); } //It's a class that's defined locally in every file that uses it. Stream loadStream = null; if (info.pccPath == UnrealObjectInfo.Me3ExplorerCustomNativeAdditionsName) { loadStream = Utilities.GetCustomAppResourceStream(pcc.Game); //string resourceFilePath = App.CustomResourceFilePath(pcc.Game); //if (File.Exists(resourceFilePath)) //{ // sourceFilePath = resourceFilePath; //} } else { string testPath = Path.Combine(MEDirectories.GetBioGamePath(pcc.Game), info.pccPath); if (File.Exists(testPath)) { loadStream = new MemoryStream(File.ReadAllBytes(testPath)); } else if (pcc.Game == MEGame.ME1) { testPath = Path.Combine(ME1Directory.DefaultGamePath, info.pccPath); if (File.Exists(testPath)) { loadStream = new MemoryStream(File.ReadAllBytes(testPath)); } } } if (loadStream == null) { //can't find file to import from. This may occur if user does not have game or neccesary dlc installed return(null); } using IMEPackage sourcePackage = MEPackageHandler.OpenMEPackageFromStream(loadStream); if (!sourcePackage.IsUExport(info.exportIndex)) { return(null); //not sure how this would happen } ExportEntry sourceClassExport = sourcePackage.GetUExport(info.exportIndex); if (sourceClassExport.ObjectName != className) { return(null); } //Will make sure that, if the class is in a package, that package will exist in pcc IEntry parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceClassExport.ParentFullPath, sourcePackage, pcc); var relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceClassExport, pcc, parent, true, out IEntry result); if (relinkResults?.Count > 0) { ListDialog ld = new ListDialog(relinkResults, "Relink report", "The following items failed to relink.", null); ld.Show(); } return(result); } catch (Exception e) { //remove added entries var entriesToRemove = new List <IEntry>(); for (int i = exportCount; i < pcc.Exports.Count; i++) { entriesToRemove.Add(pcc.Exports[i]); } for (int i = importCount; i < pcc.Imports.Count; i++) { entriesToRemove.Add(pcc.Imports[i]); } EntryPruner.TrashEntries(pcc, entriesToRemove); pcc.restoreNames(nameListBackup); return(null); } }
public static byte[] ConvertTexture2D(ExportEntry export, MEGame newGame, List <int> offsets = null, StorageTypes newStorageType = StorageTypes.empty) { MemoryStream bin = export.GetReadOnlyBinaryStream(); if (bin.Length == 0) { return(bin.ToArray()); } var os = new MemoryStream(); if (export.Game != MEGame.ME3) { bin.Skip(16); } if (newGame != MEGame.ME3) { os.WriteZeros(16);//includes fileOffset, but that will be set during save } int mipCount = bin.ReadInt32(); long mipCountPosition = os.Position; os.WriteInt32(mipCount); List <Texture2DMipInfo> mips = Texture2D.GetTexture2DMipInfos(export, export.GetProperty <NameProperty>("TextureFileCacheName")?.Value); int offsetIdx = 0; int trueMipCount = 0; for (int i = 0; i < mipCount; i++) { var storageType = (StorageTypes)bin.ReadInt32(); int uncompressedSize = bin.ReadInt32(); int compressedSize = bin.ReadInt32(); int fileOffset = bin.ReadInt32(); byte[] texture; switch (storageType) { case StorageTypes.pccUnc: texture = bin.ReadToBuffer(uncompressedSize); break; case StorageTypes.pccLZO: case StorageTypes.pccZlib: texture = bin.ReadToBuffer(compressedSize); if (offsets != null) { texture = Array.Empty <byte>(); fileOffset = offsets[offsetIdx++]; compressedSize = offsets[offsetIdx] - fileOffset; if (newStorageType != StorageTypes.empty) { storageType = newStorageType; } } break; case StorageTypes.empty: texture = new byte[0]; break; default: if (export.Game != newGame) { storageType &= (StorageTypes) ~StorageFlags.externalFile; texture = Texture2D.GetTextureData(mips[i], export.Game, MEDirectories.GetDefaultGamePath(export.Game), false); //copy in external textures } else { texture = Array.Empty <byte>(); } break; } int width = bin.ReadInt32(); int height = bin.ReadInt32(); if (newGame == MEGame.UDK && storageType == StorageTypes.empty) { continue; } trueMipCount++; os.WriteInt32((int)storageType); os.WriteInt32(uncompressedSize); os.WriteInt32(compressedSize); os.WriteInt32(fileOffset);//fileOffset will be fixed during save os.WriteFromBuffer(texture); os.WriteInt32(width); os.WriteInt32(height); } long postMipPosition = os.Position; os.JumpTo(mipCountPosition); os.WriteInt32(trueMipCount); os.JumpTo(postMipPosition); int unk1 = 0; if (export.Game != MEGame.UDK) { unk1 = bin.ReadInt32(); } if (newGame != MEGame.UDK) { os.WriteInt32(unk1); } Guid textureGuid = export.Game != MEGame.ME1 ? bin.ReadGuid() : Guid.NewGuid(); if (newGame != MEGame.ME1) { os.WriteGuid(textureGuid); } if (export.Game == MEGame.UDK) { bin.Skip(32); } if (newGame == MEGame.UDK) { os.WriteZeros(4 * 8); } if (export.Game == MEGame.ME3) { bin.Skip(4); } if (newGame == MEGame.ME3) { os.WriteInt32(0); } if (export.ClassName == "LightMapTexture2D") { int lightMapFlags = 0; if (export.Game >= MEGame.ME3) { lightMapFlags = bin.ReadInt32(); } if (newGame >= MEGame.ME3) { os.WriteInt32(0);//LightMapFlags noflag } } return(os.ToArray()); }
private static string shaderfilePath(MEGame game) => Path.Combine(MEDirectories.CookedPath(game), shaderFileName);
public ThumbnailWriter(MEDirectories.MEDirectories gameDirec) { GameDirecs = gameDirec; CachePath = GameDirecs.ThumbnailCachePath; }
public AbstractTexInfo(MEDirectories.MEDirectories direcs) : this() { GameDirecs = direcs; }
private void CheckModForAFCCompactability(DeploymentChecklistItem item) { bool hasError = false; item.HasError = false; item.ItemText = M3L.GetString(M3L.string_checkingAudioReferencesInMod); var referencedFiles = ModBeingDeployed.GetAllRelativeReferences().Select(x => Path.Combine(ModBeingDeployed.ModPath, x)).ToList(); int numChecked = 0; GameTarget validationTarget = mainWindow.InstallationTargets.FirstOrDefault(x => x.Game == ModBeingDeployed.Game); List <string> gameFiles = MEDirectories.EnumerateGameFiles(validationTarget.Game, validationTarget.TargetPath); var errors = new List <string>(); Dictionary <string, MemoryStream> cachedAudio = new Dictionary <string, MemoryStream>(); foreach (var f in referencedFiles) { if (_closed) { return; } numChecked++; item.ItemText = $@"{M3L.GetString(M3L.string_checkingAudioReferencesInMod)} [{numChecked}/{referencedFiles.Count}]"; if (f.RepresentsPackageFilePath()) { var package = MEPackageHandler.OpenMEPackage(f); var wwiseStreams = package.Exports.Where(x => x.ClassName == @"WwiseStream" && !x.IsDefaultObject).ToList(); foreach (var wwisestream in wwiseStreams) { if (_closed) { return; } //Check each reference. var afcNameProp = wwisestream.GetProperty <NameProperty>(@"Filename"); if (afcNameProp != null) { string afcNameWithExtension = afcNameProp + @".afc"; int audioSize = BitConverter.ToInt32(wwisestream.Data, wwisestream.Data.Length - 8); int audioOffset = BitConverter.ToInt32(wwisestream.Data, wwisestream.Data.Length - 4); string afcPath = null; Stream audioStream = null; var localDirectoryAFCPath = Path.Combine(Path.GetDirectoryName(wwisestream.FileRef.FilePath), afcNameWithExtension); bool isInOfficialArea = false; if (File.Exists(localDirectoryAFCPath)) { //local afc afcPath = localDirectoryAFCPath; } else { //Check game var fullPath = gameFiles.FirstOrDefault(x => Path.GetFileName(x).Equals(afcNameWithExtension, StringComparison.InvariantCultureIgnoreCase)); if (fullPath != null) { afcPath = fullPath; isInOfficialArea = MEDirectories.IsInBasegame(afcPath, validationTarget) || MEDirectories.IsInOfficialDLC(afcPath, validationTarget); } else if (cachedAudio.TryGetValue(afcNameProp.Value.Name, out var cachedAudioStream)) { audioStream = cachedAudioStream; //isInOfficialArea = true; //cached from vanilla SFAR } else if (MEDirectories.OfficialDLC(validationTarget.Game).Any(x => afcNameProp.Value.Name.StartsWith(x))) { var dlcName = afcNameProp.Value.Name.Substring(0, afcNameProp.Value.Name.LastIndexOf(@"_", StringComparison.InvariantCultureIgnoreCase)); var audio = VanillaDatabaseService.FetchFileFromVanillaSFAR(validationTarget, dlcName, afcNameWithExtension); if (audio != null) { cachedAudio[afcNameProp.Value.Name] = audio; } audioStream = audio; //isInOfficialArea = true; as this is in a vanilla SFAR we don't test against this since it will be correct. continue; } else { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_couldNotFindReferencedAFC, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath, afcNameProp.ToString())); continue; } } if (afcPath != null) { audioStream = new FileStream(afcPath, FileMode.Open); } try { audioStream.Seek(audioOffset, SeekOrigin.Begin); if (audioStream.ReadStringASCIINull(4) != @"RIFF") { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_invalidAudioPointer, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath)); if (audioStream is FileStream) { audioStream.Close(); } continue; } //attempt to seek audio length. audioStream.Seek(audioSize + 4, SeekOrigin.Current); //Check if this file is in basegame if (isInOfficialArea) { //Verify offset is not greater than vanilla size var vanillaInfo = VanillaDatabaseService.GetVanillaFileInfo(validationTarget, afcPath.Substring(validationTarget.TargetPath.Length + 1)); if (vanillaInfo == null) { Crashes.TrackError(new Exception($@"Vanilla information was null when performing vanilla file check for {afcPath.Substring(validationTarget.TargetPath.Length + 1)}")); } if (audioOffset >= vanillaInfo[0].size) { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; errors.Add(M3L.GetString(M3L.string_interp_audioStoredInOfficialAFC, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath)); } } if (audioStream is FileStream) { audioStream.Close(); } } catch (Exception e) { hasError = true; item.Icon = FontAwesomeIcon.TimesCircle; item.Foreground = Brushes.Red; item.Spinning = false; if (audioStream is FileStream) { audioStream.Close(); } errors.Add(M3L.GetString(M3L.string_errorValidatingAudioReference, wwisestream.FileRef.FilePath, wwisestream.GetInstancedFullPath, e.Message)); continue; } } } } } if (!hasError) { item.Foreground = Brushes.Green; item.Icon = FontAwesomeIcon.CheckCircle; item.ItemText = M3L.GetString(M3L.string_noAudioIssuesWereDetected); item.ToolTip = M3L.GetString(M3L.string_validationOK); } else { item.Errors = errors; item.ItemText = M3L.GetString(M3L.string_audioIssuesWereDetected); item.ToolTip = M3L.GetString(M3L.string_validationFailed); } item.HasError = hasError; cachedAudio.Clear(); }
public TPFTexInfo(string file, ZipReader.ZipEntryFull entry, MEDirectories.MEDirectories gameDirecs) : this(gameDirecs) { ZipEntry = entry; if (Path.IsPathRooted(file)) { FilePath = Path.GetDirectoryName(file); FileName = Path.GetFileName(file); } else FileName = file; }
public PCCEntry(string name, int expid, MEDirectories.MEDirectories gameDirecs) { Name = name; ExpID = expid; basePathLength = gameDirecs.BasePathLength; }
/// <summary> /// Installs the specific version of an ASI to the specified target /// </summary> /// <param name="modVersion"></param> /// <param name="target"></param> /// <param name="forceSource">Null to let application choose the source, true to force online, false to force local cache. This parameter is used for testing</param> /// <returns></returns> public static bool InstallASIToTarget(ASIModVersion asi, GameTarget target, bool?forceSource = null) { if (asi.Game != target.Game) { throw new Exception($@"ASI {asi.Name} cannot be installed to game {target.Game}"); } Log.Information($@"Processing ASI installation request: {asi.Name} v{asi.Version} -> {target.TargetPath}"); string destinationFilename = $@"{asi.InstalledPrefix}-v{asi.Version}.asi"; string cachedPath = Path.Combine(CachedASIsFolder, destinationFilename); string destinationDirectory = MEDirectories.ASIPath(target); if (!Directory.Exists(destinationDirectory)) { Log.Information(@"Creating ASI directory in game: " + destinationDirectory); Directory.CreateDirectory(destinationDirectory); } string finalPath = Path.Combine(destinationDirectory, destinationFilename); // Delete existing ASIs from the same group to ensure we don't install the same mod var existingSameGroupMods = target.GetInstalledASIs().OfType <KnownInstalledASIMod>().Where(x => x.AssociatedManifestItem.OwningMod == asi.OwningMod).ToList(); bool hasExistingVersionOfModInstalled = false; if (existingSameGroupMods.Any()) { foreach (var v in existingSameGroupMods) { if (v.Hash == asi.Hash && !forceSource.HasValue && !hasExistingVersionOfModInstalled) //If we are forcing a source, we should always install. Delete duplicates past the first one { Log.Information($@"{v.AssociatedManifestItem.Name} is already installed. We will not remove the existing correct installed ASI for this install request"); hasExistingVersionOfModInstalled = true; continue; //Don't delete this one. We are already installed. There is no reason to install it again. } Log.Information($@"Deleting existing ASI from same group: {v.InstalledPath}"); v.Uninstall(); } } if (hasExistingVersionOfModInstalled && !forceSource.HasValue) //Let app decide { return(true); // This asi was "Installed" (because it was already installed). } // Install the ASI if (forceSource == null || forceSource.Value == false) { Debug.WriteLine("Hit me"); } string md5; bool useLocal = forceSource.HasValue && !forceSource.Value; // false (forceLocal) if (!useLocal && !forceSource.HasValue) { useLocal = File.Exists(cachedPath); } if (useLocal) { //Check hash first md5 = Utilities.CalculateMD5(cachedPath); if (md5 == asi.Hash) { Log.Information($@"Copying ASI from cached library to destination: {cachedPath} -> {finalPath}"); File.Copy(cachedPath, finalPath, true); Log.Information($@"Installed ASI to {finalPath}"); Analytics.TrackEvent(@"Installed ASI", new Dictionary <string, string>() { { @"Filename", Path.GetFileNameWithoutExtension(finalPath) } }); return(true); } } if (!forceSource.HasValue || forceSource.Value) { WebRequest request = WebRequest.Create(asi.DownloadLink); Log.Information(@"Fetching remote ASI from server"); using WebResponse response = request.GetResponse(); var memoryStream = new MemoryStream(); response.GetResponseStream().CopyTo(memoryStream); //MD5 check on file for security md5 = Utilities.CalculateMD5(memoryStream); if (md5 != asi.Hash) { //ERROR! Log.Error(@"Downloaded ASI did not match the manifest! It has the wrong hash."); return(false); } Log.Information(@"Fetched remote ASI from server. Installing ASI to " + finalPath); memoryStream.WriteToFile(finalPath); Log.Information(@"ASI successfully installed."); Analytics.TrackEvent(@"Installed ASI", new Dictionary <string, string>() { { @"Filename", Path.GetFileNameWithoutExtension(finalPath) } }); //Cache ASI if (!Directory.Exists(CachedASIsFolder)) { Log.Information(@"Creating cached ASIs folder"); Directory.CreateDirectory(CachedASIsFolder); } Log.Information(@"Caching ASI to local ASI library: " + cachedPath); memoryStream.WriteToFile(cachedPath); return(true); } // We could not install the ASI return(false); }
public static async void BeginFlow(MainWindow window) { // PRE LIBRARY LOAD RegistryHandler.RegistrySettingsPath = @"HKEY_CURRENT_USER\Software\MassEffect2Randomizer"; RegistryHandler.CurrentUserRegistrySubpath = @"Software\MassEffect2Randomizer"; LegendaryExplorerCoreLib.SetSynchronizationContext(TaskScheduler.FromCurrentSynchronizationContext()); try { // This is in a try catch because this is a critical no-crash zone that is before launch window.Title = $"Mass Effect 2 Randomizer {App.AppVersion}"; } catch { } if (Utilities.GetExecutablePath().StartsWith(Path.GetTempPath(), StringComparison.InvariantCultureIgnoreCase)) { // Running from temp! This is not allowed await window.ShowMessageAsync("Cannot run from temp directory", $"Mass Effect 2 Randomizer cannot be run from the system's Temp directory. If this executable was run from within an archive, it needs to be extracted first."); Environment.Exit(1); } var pd = await window.ShowProgressAsync("Starting up", $"Mass Effect 2 Randomizer is starting up. Please wait."); pd.SetIndeterminate(); NamedBackgroundWorker bw = new NamedBackgroundWorker("StartupThread"); bw.DoWork += (a, b) => { ALOTInstallerCoreLib.Startup(SetWrapperLogger, RunOnUIThread, startTelemetry, stopTelemetry, $"Mass Effect 2 Randomizer {App.AppVersion} starting up", false); // Logger is now available // Setup telemetry handlers CoreAnalytics.TrackEvent = TelemetryController.TrackEvent; CoreCrashes.TrackError = TelemetryController.TrackError; CoreCrashes.TrackError2 = TelemetryController.TrackError2; CoreCrashes.TrackError3 = TelemetryController.TrackError3; // Setup the InteropPackage for the update check #region Update interop CancellationTokenSource ct = new CancellationTokenSource(); AppUpdateInteropPackage interopPackage = new AppUpdateInteropPackage() { GithubOwner = "Mgamerz", GithubReponame = "MassEffect2Randomizer", UpdateAssetPrefix = "ME2Randomizer", UpdateFilenameInArchive = "ME2Randomizer.exe", ShowUpdatePromptCallback = (title, text, updateButtonText, declineButtonText) => { bool response = false; object syncObj = new object(); Application.Current.Dispatcher.Invoke(async() => { if (Application.Current.MainWindow is MainWindow mw) { var result = await mw.ShowMessageAsync(title, text, MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings() { AffirmativeButtonText = updateButtonText, NegativeButtonText = declineButtonText, DefaultButtonFocus = MessageDialogResult.Affirmative }, 75); response = result == MessageDialogResult.Affirmative; lock (syncObj) { Monitor.Pulse(syncObj); } } }); lock (syncObj) { Monitor.Wait(syncObj); } return(response); }, ShowUpdateProgressDialogCallback = (title, initialmessage, canCancel) => { // We don't use this as we are already in a progress dialog pd.SetCancelable(canCancel); pd.SetMessage(initialmessage); pd.SetTitle(title); }, SetUpdateDialogTextCallback = s => { pd.SetMessage(s); }, ProgressCallback = (done, total) => { pd.SetProgress(done * 1d / total); pd.SetMessage($"Downloading update {FileSize.FormatSize(done)} / {FileSize.FormatSize(total)}"); }, ProgressIndeterminateCallback = () => { pd.SetIndeterminate(); }, ShowMessageCallback = (title, message) => { object syncObj = new object(); Application.Current.Dispatcher.Invoke(async() => { if (Application.Current.MainWindow is MainWindow mw) { await mw.ShowMessageAsync(title, message); lock (syncObj) { Monitor.Pulse(syncObj); } } }); lock (syncObj) { Monitor.Wait(syncObj); } }, NotifyBetaAvailable = () => { App.BetaAvailable = true; }, DownloadCompleted = () => { pd.SetCancelable(false); }, cancellationTokenSource = ct, ApplicationName = "Mass Effect 2 Randomizer", RequestHeader = "ME2Randomizer", ForcedUpgradeMaxReleaseAge = 3 }; #endregion pd.SetMessage("Checking for application updates"); pd.Canceled += (sender, args) => { ct.Cancel(); }; AppUpdater.PerformGithubAppUpdateCheck(interopPackage); // If user aborts download pd.SetCancelable(false); pd.SetIndeterminate(); pd.SetTitle("Starting up"); void setStatus(string message) { pd.SetIndeterminate(); pd.SetMessage(message); } GameTarget target = null; try { pd.SetMessage("Loading Mass Effect 2 Randomizer framework"); ToolTipService.ShowOnDisabledProperty.OverrideMetadata(typeof(Control), new FrameworkPropertyMetadata(true)); ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(int.MaxValue)); ALOTInstallerCoreLib.PostCriticalStartup(x => pd.SetMessage(x), RunOnUIThread, false); #if __LE2__ LE2Directory.ReloadDefaultGamePath(true); if (LE2Directory.DefaultGamePath != null) { GameTarget gt = new GameTarget(MEGame.LE2, LE2Directory.DefaultGamePath, true); if (gt.ValidateTarget() == null) { Locations.SetTarget(gt, false); } } #endif MEPackageHandler.GlobalSharedCacheEnabled = false; // ME2R does not use the global shared cache. handleM3Passthrough(); target = Locations.GetTarget(MERFileSystem.Game); if (target == null) { var gamePath = MEDirectories.GetDefaultGamePath(MERFileSystem.Game); if (Directory.Exists(gamePath)) { target = new GameTarget(MERFileSystem.Game, gamePath, true); var validationFailedReason = target.ValidateTarget(); if (validationFailedReason == null) { // CHECK NOT TEXTURE MODIFIED if (target.TextureModded) { MERLog.Error($@"Game target is texture modded: {target.TargetPath}. This game target is not targetable by ME2R"); object o = new object(); Application.Current.Dispatcher.Invoke(async() => { if (Application.Current.MainWindow is MainWindow mw) { await mw.ShowMessageAsync("Mass Effect 2 target is texture modded", $"The game located at {target.TargetPath} has had textures modified. Mass Effect 2 Randomizer cannot randomize texture modified games, as it adds package files. If you want to texture mod your game, it must be done after randomization.", ContentWidthPercent: 75); lock (o) { Monitor.Pulse(o); } } }); lock (o) { Monitor.Wait(o); } } // We still set target so we can restore game if necessary Locations.SetTarget(target, false); } } } pd.SetMessage("Performing startup checks"); MERStartupCheck.PerformStartupCheck((title, message) => { object o = new object(); Application.Current.Dispatcher.Invoke(async() => { if (Application.Current.MainWindow is MainWindow mw) { await mw.ShowMessageAsync(title, message, ContentWidthPercent: 75); lock (o) { Monitor.Pulse(o); } } }); lock (o) { Monitor.Wait(o); } }, x => pd.SetMessage(x)); // force initial refresh MERPeriodicRefresh(null, null); } catch (Exception e) { MERLog.Exception(e, @"There was an error starting up the framework!"); } pd.SetMessage("Preparing interface"); Thread.Sleep(250); // This will allow this message to show up for moment so user can see it. Application.Current.Dispatcher.Invoke(async() => { if (Application.Current.MainWindow is MainWindow mw) { mw.SetupTargetDescriptionText(); var backupStatus = BackupService.GetBackupStatus(MERFileSystem.Game); mw.BackupRestoreText = backupStatus?.BackupActionText; mw.BackupRestore_Button.ToolTip = backupStatus != null && backupStatus.BackedUp ? "Click to restore game/uninstall randomizer mod" : "Click to backup game"; mw.FinalizeInterfaceLoad(); /* * if (!hasWorkingMEM) * { * await mw.ShowMessageAsync("Required components are not available", * "Some components for installation are not available, likely due to network issues (blocking, no internet, etc). To install these components, folow the 'How to install the Installer Support Package' directions on any of the ALOT pages on NexusMods. The installer will not work without these files installed.", * ContentWidthPercent: 75); * }*/ PeriodicRefresh.OnPeriodicRefresh += MERPeriodicRefresh; } }); }; bw.RunWorkerCompleted += async(a, b) => { // Post critical startup Random random = new Random(); var preseed = random.Next(); window.ImageCredits.ReplaceAll(ImageCredit.LoadImageCredits("imagecredits.txt", false)); window.ContributorCredits.ReplaceAll(window.GetContributorCredits()); window.LibraryCredits.ReplaceAll(LibraryCredit.LoadLibraryCredits("librarycredits.txt")); #if DEBUG window.SeedTextBox.Text = 529572808.ToString(); #else window.SeedTextBox.Text = preseed.ToString(); #endif window.TextBlock_AssemblyVersion.Text = $"Version {App.AppVersion}"; window.SelectedRandomizeMode = MainWindow.RandomizationMode.ERandomizationMode_SelectAny; var hasFirstRun = RegistryHandler.GetRegistrySettingBool(MainWindow.SETTING_FIRSTRUN); if (hasFirstRun == null || !hasFirstRun.Value) { window.FirstRunFlyoutOpen = true; } await pd.CloseAsync(); }; bw.RunWorkerAsync(); }
/// <summary> /// Checks if the specified DLC folder name is protected (official DLC names and __metadata) /// </summary> /// <param name="dlcFolderName">DLC folder name (DLC_CON_MP2)</param> /// <param name="game">Game to test against</param> /// <returns>True if protected, false otherwise</returns> internal static bool IsProtectedDLCFolder(string dlcFolderName, Mod.MEGame game) => dlcFolderName.Equals("__metadata", StringComparison.InvariantCultureIgnoreCase) && MEDirectories.OfficialDLC(game).Contains(dlcFolderName, StringComparer.InvariantCultureIgnoreCase);
public TPFTexInfo(MEDirectories.MEDirectories gameDirecs) : base(gameDirecs) { GameDirecs = gameDirecs; }