/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> against which to run the script.</param> public Fallout3ModInstallScript(fomod p_fomodMod, ModInstallerBase p_mibInstaller) : base(p_fomodMod, p_mibInstaller) { //m_misScript = new ModInstallScript(p_fomodMod); BsaManager = new BsaManager(); TextureManager = new TextureManager(); }
/// <summary> /// Scans the mods folder for fomods that have versions that differ from their versions in the install log. /// </summary> /// <remarks> /// If fomods with versions that differ from those in the install log are found, the use is asked whether /// to replace or upgrade the fomod. Replacing the fomod merely changes the version in the install log, /// but makes no system changes. Upgrading the fomod performs an in-place upgrade. /// </remarks> public void Scan() { IList<FomodInfo> lstMods = InstallLog.Current.GetVersionedModList(); fomod fomodMod = null; List<fomod> lstModsToUpgrade = new List<fomod>(); List<fomod> lstModsToReplace = new List<fomod>(); foreach (FomodInfo fifMod in lstMods) { #if TRACE Trace.WriteLine("Scanning " + Path.Combine(Program.GameMode.ModDirectory, fifMod.BaseName + ".fomod")); #endif fomodMod = new fomod(Path.Combine(Program.GameMode.ModDirectory, fifMod.BaseName + ".fomod")); if (!fomodMod.HumanReadableVersion.Equals(fifMod.Version)) { switch (MessageBox.Show(String.Format(m_strUpgradeMessage, fomodMod.ModName, fifMod.Version, fomodMod.HumanReadableVersion), "Upgrade", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) { case DialogResult.Yes: lstModsToUpgrade.Add(fomodMod); break; case DialogResult.No: lstModsToReplace.Add(fomodMod); break; } } } Replace(lstModsToReplace); Upgrade(lstModsToUpgrade); }
/// <summary> /// The factory method that returns the appropriate parser for the given configuration file. /// </summary> /// <param name="p_xmlConfig">The configuration file for which to return a parser.</param> /// <param name="p_fomodMod">The mod whose configuration file is being parsed.</param> /// <param name="p_dsmSate">The state of the install.</param> /// <returns>The appropriate parser for the given configuration file.</returns> /// <exception cref="ParserException">Thrown if no parser is found for the given configuration file.</exception> public static Parser GetParser(XmlDocument p_xmlConfig, fomod p_fomodMod, DependencyStateManager p_dsmSate) { var strConfigVersion = "1.0"; var strSchemaName = p_xmlConfig.SelectSingleNode("config").Attributes["xsi:noNamespaceSchemaLocation"].InnerText.ToLowerInvariant(); var intStartPos = strSchemaName.LastIndexOf("modconfig") + 9; if (intStartPos > 8) { var intLength = strSchemaName.Length - intStartPos - 4; if (intLength > 0) { strConfigVersion = strSchemaName.Substring(intStartPos, intLength); } } var pexParserExtension = Program.GameMode.GetParserExtension(strConfigVersion); switch (strConfigVersion) { case "1.0": return new Parser10(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension); case "2.0": return new Parser20(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension); case "3.0": return new Parser30(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension); case "4.0": return new Parser40(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension); case "5.0": return new Parser50(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension); } throw new ParserException("Unrecognized Module Configuration version (" + strConfigVersion + "). Perhaps a newer version of FOMM is required."); }
/// <summary> /// Scans the mods folder for fomods that have versions that differ from their versions in the install log. /// </summary> /// <remarks> /// If fomods with versions that differ from those in the install log are found, the use is asked whether /// to replace or upgrade the fomod. Replacing the fomod merely changes the version in the install log, /// but makes no system changes. Upgrading the fomod performs an in-place upgrade. /// </remarks> public void Scan() { var lstMods = InstallLog.Current.GetVersionedModList(); var lstModsToUpgrade = new List <fomod>(); var lstModsToReplace = new List <fomod>(); foreach (var fifMod in lstMods) { var fomodMod = new fomod(Path.Combine(Program.GameMode.ModDirectory, fifMod.BaseName + ".fomod")); if (!fomodMod.HumanReadableVersion.Equals(fifMod.Version)) { switch ( MessageBox.Show( String.Format(m_strUpgradeMessage, fomodMod.ModName, fifMod.Version, fomodMod.HumanReadableVersion), "Upgrade", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) { case DialogResult.Yes: lstModsToUpgrade.Add(fomodMod); break; case DialogResult.No: lstModsToReplace.Add(fomodMod); break; } } } Replace(lstModsToReplace); Upgrade(lstModsToUpgrade); }
/// <summary> /// A simple constructor that initializes teh object with the given values. /// </summary> /// <param name="p_xmlConfig">The modules configuration file.</param> /// <param name="p_fomodMod">The mod whose configuration file we are parsing.</param> /// <param name="p_dsmSate">The state of the install.</param> /// <param name="p_pexParserExtension">The parser extension that provides game-specific config file parsing.</param> public Parser(XmlDocument p_xmlConfig, fomod p_fomodMod, DependencyStateManager p_dsmSate, ParserExtension p_pexParserExtension) { m_pexParserExtension = p_pexParserExtension; m_xmlConfig = p_xmlConfig; m_fomodMod = p_fomodMod; m_dsmSate = p_dsmSate; validateModuleConfig(); }
/// <summary> /// A simple constructor that initializes teh object with the given values. /// </summary> /// <param name="p_xmlConfig">The modules configuration file.</param> /// <param name="p_fomodMod">The mod whose configuration file we are parsing.</param> /// <param name="p_dsmSate">The state of the install.</param> /// <param name="p_pexParserExtension">The parser extension that provides game-specific config file parsing.</param> public Parser(XmlDocument p_xmlConfig, fomod p_fomodMod, DependencyStateManager p_dsmSate, ParserExtension p_pexParserExtension) { m_pexParserExtension = p_pexParserExtension; XmlConfig = p_xmlConfig; Fomod = p_fomodMod; StateManager = p_dsmSate; validateModuleConfig(); }
/// <summary> /// Called when the conflict detector has found a conflict. /// </summary> /// <remarks> /// This adds a message to the appropriate plugin's info box, and changes the plugin's /// node's background colour as appropriate. /// </remarks> /// <param name="sender">The object that trigger the event.</param> /// <param name="e">A <see cref="ConflictDetectedEventArgs" /> describing the event arguments.</param> private void cdrDetector_ConflictDetected(object sender, ConflictDetectedEventArgs e) { var stbMessage = new StringBuilder(); var lstBackgroundColours = new List <Color> { Color.LightSkyBlue, Color.Yellow, Color.Red }; var intColourIndex = 0; switch (e.ConflictInfo.Severity) { case CriticalRecordInfo.ConflictSeverity.Conflict: stbMessage.Append(@"\b \cf1 CONFLICT\cf0 :\b0 "); intColourIndex = 2; break; case CriticalRecordInfo.ConflictSeverity.Warning: stbMessage.Append(@"\b \cf2 WARNING\cf0 :\b0 "); intColourIndex = 1; break; case CriticalRecordInfo.ConflictSeverity.Info: stbMessage.Append(@"\b \cf3 INFO\cf0 :\b0 "); intColourIndex = 0; break; } var clrHighlight = lstBackgroundColours[intColourIndex]; if (m_pfpFormatProvider.HasFormat(e.ConflictedPlugin.Name)) { var pftFormat = m_pfpFormatProvider.GetFormat(e.ConflictedPlugin.Name); if (pftFormat.Highlight.HasValue && (lstBackgroundColours.IndexOf(pftFormat.Highlight.Value) > intColourIndex)) { clrHighlight = pftFormat.Highlight.Value; } } if (InstallLog.Current.GetCurrentFileOwnerName(e.ConflictingPlugin.Name) == null) { stbMessage.AppendFormat( "Form Id \\b {0:x8}\\b0 is overridden by \\b {1}\\b0 .\\par \\pard\\li720\\sl240\\slmult1 {2}\\par \\pard\\sl240\\slmult1 ", e.FormId, e.ConflictingPlugin.Name, e.ConflictInfo.Reason); } else { var fomodMod = new fomod(Path.Combine(Program.GameMode.ModDirectory, InstallLog.Current.GetCurrentFileOwnerName(e.ConflictingPlugin.Name) + ".fomod")); stbMessage.AppendFormat( "Form Id \\b {0:x8}\\b0 is overridden by \\b {1}\\b0 in \\b {2}\\b0 .\\par \\pard\\li720\\sl240\\slmult1 {3}\\par \\pard\\sl240\\slmult1 ", e.FormId, e.ConflictingPlugin.Name, fomodMod.ModName, e.ConflictInfo.Reason); } m_pfpFormatProvider.AddFormat(e.ConflictedPlugin.Name, clrHighlight, stbMessage.ToString()); }
/// <summary> /// Upgrades the Install Log to the current version from version 0.1.0.0. /// </summary> /// <remarks> /// This method is called by a background worker to perform the actual upgrade. /// </remarks> protected override void DoUpgrade() { var xmlInstallLog = new XmlDocument(); xmlInstallLog.Load(InstallLog.Current.InstallLogPath); var xndRoot = xmlInstallLog.SelectSingleNode("installLog"); if (xndRoot == null) { return; } var lstMods = InstallLog.Current.GetModList(); var xndSdpEdits = xndRoot.SelectSingleNode("sdpEdits"); if (xndSdpEdits != null) { ProgressWorker.OverallProgressStep = 1; ProgressWorker.OverallProgressMaximum = lstMods.Count + xndSdpEdits.ChildNodes.Count; ProgressWorker.ShowItemProgress = false; //remove the sdp edit node... xndSdpEdits.ParentNode.RemoveChild(xndSdpEdits); //...and replace it with the game-specific edits node var xndGameSpecificsValueEdits = xndRoot.AppendChild(xmlInstallLog.CreateElement("gameSpecificEdits")); foreach (XmlNode xndSdpEdit in xndSdpEdits.ChildNodes) { ProgressWorker.StepOverallProgress(); var xndGameSpecificsValueEdit = xndGameSpecificsValueEdits.AppendChild(xmlInstallLog.CreateElement("edit")); var strValueKey = $"sdp:{xndGameSpecificsValueEdits.Attributes["package"].Value}/{xndGameSpecificsValueEdits.Attributes["shader"].Value}"; xndGameSpecificsValueEdit.Attributes.Append(xmlInstallLog.CreateAttribute("key")).Value = strValueKey; xndGameSpecificsValueEdit.AppendChild(xndSdpEdit.FirstChild.Clone()); } } xmlInstallLog.Save(InstallLog.Current.InstallLogPath); //now update the mod info foreach (var strMod in lstMods) { ProgressWorker.StepOverallProgress(); if (strMod.Equals(InstallLog.ORIGINAL_VALUES) || strMod.Equals(InstallLog.FOMM)) { continue; } var strModPath = Path.Combine(Program.GameMode.ModDirectory, strMod + ".fomod"); var fomodMod = new fomod(strModPath); InstallLog.Current.UpdateMod(fomodMod); } InstallLog.Current.SetInstallLogVersion(InstallLog.CURRENT_VERSION); InstallLog.Current.Save(); }
/// <summary> /// The factory method that returns the appropriate parser for the given configuration file. /// </summary> /// <param name="p_xmlConfig">The configuration file for which to return a parser.</param> /// <param name="p_fomodMod">The mod whose configuration file is being parsed.</param> /// <param name="p_dsmSate">The state of the install.</param> /// <returns>The appropriate parser for the given configuration file.</returns> /// <exception cref="ParserException">Thrown if no parser is found for the given configuration file.</exception> public static Parser GetParser(XmlDocument p_xmlConfig, fomod p_fomodMod, DependencyStateManager p_dsmSate) { var strConfigVersion = "1.0"; var strSchemaName = p_xmlConfig.SelectSingleNode("config").Attributes["xsi:noNamespaceSchemaLocation"].InnerText.ToLowerInvariant(); var intStartPos = strSchemaName.LastIndexOf("modconfig") + 9; if (intStartPos > 8) { var intLength = strSchemaName.Length - intStartPos - 4; if (intLength > 0) { strConfigVersion = strSchemaName.Substring(intStartPos, intLength); } } var pexParserExtension = Program.GameMode.GetParserExtension(strConfigVersion); switch (strConfigVersion) { case "1.0": return(new Parser10(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension)); case "2.0": return(new Parser20(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension)); case "3.0": return(new Parser30(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension)); case "4.0": return(new Parser40(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension)); case "5.0": return(new Parser50(p_xmlConfig, p_fomodMod, p_dsmSate, pexParserExtension)); } throw new ParserException("Unrecognized Module Configuration version (" + strConfigVersion + "). Perhaps a newer version of FOMM is required."); }
/// <summary> /// Creates a fomod from a source. /// </summary> /// <remarks> /// The source can be a folder or an archive. /// </remarks> /// <param name="p_strPath">The path to the source from which to create the fomod.</param> /// <returns>The path to the new fomod if it was successfully built; <lang langref="null" /> otherwise.</returns> public IList <string> BuildFomodFromSource(string p_strPath) { var strSource = p_strPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var lstPackedFOModPaths = new List <string>(); var booCreateFromFolder = true; if (File.Exists(strSource)) { booCreateFromFolder = false; if (!Archive.IsArchive(strSource)) { throw new ArgumentException("Unrecognized file format.", "p_strPath"); } string[] strFOMods; using (var arcMod = new Archive(strSource)) { strFOMods = arcMod.GetFiles(null, "*.fomod"); if ((strFOMods.Length == 0) && (arcMod.VolumeFileNames.Length > 1)) { if ( MessageBox.Show( "This mod consists of " + arcMod.VolumeFileNames.Length + " files. It needs to be extracted and repacked.", "Repack Required", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel) { return(lstPackedFOModPaths); } booCreateFromFolder = true; } } if (!booCreateFromFolder) { if (strFOMods.Length > 0) { foreach (var strFOMod in strFOMods) { var strNewPath = Path.Combine(Program.GameMode.ModDirectory, Path.GetFileName(strFOMod)); if (CheckFileName(ref strNewPath)) { using (var szeExtractor = Archive.GetExtractor(strSource)) { using (var fsmFOMod = new FileStream(strNewPath, FileMode.Create)) { szeExtractor.ExtractFile(strFOMod, fsmFOMod); } } lstPackedFOModPaths.Add(strNewPath); } } } else { var mof = new fomod(strSource, false); if (!mof.HasInstallScript && mof.RequiresScript) { if ( MessageBox.Show( "This mod requires a script to install properly, but doesn't have one." + Environment.NewLine + "Would you like to continue?", "Missing Script", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.No) { return(lstPackedFOModPaths); } } //remove the file extension var strPackedFomodPath = Path.GetFileNameWithoutExtension(strSource); strPackedFomodPath = Path.Combine(Program.GameMode.ModDirectory, strPackedFomodPath); if (!strPackedFomodPath.EndsWith(".fomod", StringComparison.OrdinalIgnoreCase)) { strPackedFomodPath += ".fomod"; } var strNewPath = strPackedFomodPath; if (CheckFileName(ref strNewPath)) { FileUtil.ForceDelete(strNewPath); File.Copy(strSource, strNewPath, true); lstPackedFOModPaths.Add(strNewPath); } } } } if (booCreateFromFolder) { string strFomodName; if (File.Exists(strSource)) { //remove the file extension strFomodName = Path.GetFileNameWithoutExtension(strSource); } else { var intLastSeparatorPos = strSource.LastIndexOfAny(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); strFomodName = strSource.Substring(intLastSeparatorPos + 1); } var strPackedFomodPath = Path.Combine(Program.GameMode.ModDirectory, strFomodName + ".fomod"); strPackedFomodPath = GenerateFomod(new BuildFomodArgs(strFomodName, strSource, null, strPackedFomodPath)); if (!String.IsNullOrEmpty(strPackedFomodPath)) { lstPackedFOModPaths.Add(strPackedFomodPath); } } return(lstPackedFOModPaths); }
/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> to be upgraded.</param> internal ModUpgrader(fomod p_fomodMod) : this(p_fomodMod, p_fomodMod.BaseName) {}
/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> to be upgraded.</param> internal ModUpgrader(fomod p_fomodMod, string p_strOldBaseName) : base(new UpgradeFomod(p_fomodMod.filepath)) { m_fomodOriginalMod = p_fomodMod; ((UpgradeFomod)Fomod).SetBaseName(p_strOldBaseName); }
/// <summary> /// Adds a mod to the install log. /// </summary> /// <remarks> /// Adding a mod to the install log assigns it a key. Keys are used to track file and /// edit versions. /// </remarks> /// <param name="p_fomodMod">The <see cref="fomod"/> being added.</param> protected internal void AddMod(fomod p_fomodMod) { if (!m_dicModList.ContainsKey(p_fomodMod.BaseName)) { XmlNode xndMod = AddMod(p_fomodMod.BaseName); if (xndMod == null) return; XmlNode xndVersion = xndMod.AppendChild(xmlDoc.CreateElement("version")); xndVersion.Attributes.Append(xmlDoc.CreateAttribute("machineVersion")); xndVersion.Attributes["machineVersion"].InnerText = p_fomodMod.MachineVersion.ToString(); xndVersion.InnerText = p_fomodMod.HumanReadableVersion; } }
/// <summary> /// Merges the installed and edited components in the given <see cref="InstallLogMergeModule"/> /// into the install log for the specified mod. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod"/> for which the /// installs and edits where made.</param> /// <param name="p_ilmMergeModule">The installs and edits that where made as part of the /// <see cref="fomod"/>'s installation.</param> public void Merge(fomod p_fomodMod, InstallLogMergeModule p_ilmMergeModule) { AddMod(p_fomodMod); processMergeModule(p_fomodMod.BaseName, p_ilmMergeModule); }
/// <summary> /// Upgrades the installed files log entries. /// </summary> /// <remarks> /// This analyses the mods and determines, as best as possible, who owns which files, and attempts /// to reconstruct the install order. It populates the overwrites folder with the files that, as far /// as can be determined, belong there. This resulting information is then put in the new install log. /// </remarks> /// <param name="p_xmlModInstallLog">The current mod install log we are parsing to upgrade.</param> /// <param name="p_strModInstallLogPath">The path to the current mod install log.</param> /// <param name="p_strModBaseName">The base name of the mod whose install log is being parsed.</param> private void UpgradeInstalledFiles(XmlDocument p_xmlModInstallLog, fomod p_fomodMod, string p_strModBaseName) { var intDataPathStartPos = Program.GameMode.PluginsPath.Trim(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar).Length + 1; var xnlFiles = p_xmlModInstallLog.SelectNodes("descendant::installedFiles/*"); foreach (XmlNode xndFile in xnlFiles) { var strFile = xndFile.InnerText; if (!File.Exists(strFile)) { continue; } var strDataRelativePath = strFile.Substring(intDataPathStartPos); var crcDiskFile = new Crc32(); var crcFomodFile = new Crc32(); crcDiskFile.Update(File.ReadAllBytes(strFile)); if (!p_fomodMod.ContainsFile(strDataRelativePath)) { //we don't know if this mod owns the file, so let's assume // it doesn't //put this mod's file into the overwrites directory. // we can't get the original file from the fomod, // so we'll use the existing file instead. this isn't // strictly correct, but it is inline with the behaviour // of the fomm version we are upgrading from var strDirectory = Path.GetDirectoryName(strDataRelativePath); var strBackupPath = Path.Combine(Program.GameMode.OverwriteDirectory, strDirectory); var strModKey = InstallLog.Current.GetModKey(p_strModBaseName); if (!Directory.Exists(strBackupPath)) { FileManager.CreateDirectory(strBackupPath); } strBackupPath = Path.Combine(strBackupPath, strModKey + "_" + Path.GetFileName(strDataRelativePath)); FileManager.Copy(Path.Combine(Program.GameMode.PluginsPath, strDataRelativePath), strBackupPath, true); InstallLog.Current.PrependDataFile(p_strModBaseName, strDataRelativePath); //however, it may own the file, so let's make it the default owner for now // unless we already know who the owner is if (!FileOwnerIsKnown(strDataRelativePath)) { m_dicDefaultFileOwners[strDataRelativePath] = p_strModBaseName; } continue; } var bteFomodFile = p_fomodMod.GetFileContents(strDataRelativePath); crcFomodFile.Update(bteFomodFile); if (!crcDiskFile.Value.Equals(crcFomodFile.Value) || FileOwnerIsKnown(strDataRelativePath)) { //either: // 1) another mod owns the file // 2) according to the crc we own this file, however we have already found // an owner. this could happen beacue two mods use the same version // of a file, or there is a crc collision. //either way, put this mod's file into // the overwrites directory var strDirectory = Path.GetDirectoryName(strDataRelativePath); var strBackupPath = Path.Combine(Program.GameMode.OverwriteDirectory, strDirectory); var strModKey = InstallLog.Current.GetModKey(p_strModBaseName); if (!Directory.Exists(strBackupPath)) { FileManager.CreateDirectory(strBackupPath); } strBackupPath = Path.Combine(strBackupPath, strModKey + "_" + Path.GetFileName(strDataRelativePath)); FileManager.WriteAllBytes(strBackupPath, bteFomodFile); InstallLog.Current.PrependDataFile(p_strModBaseName, strDataRelativePath); } else { //this mod owns the file, so append it to the list of installing mods InstallLog.Current.AddDataFile(p_strModBaseName, strDataRelativePath); //we also have to displace the mod that is currently the default owner if (m_dicDefaultFileOwners.ContainsKey(strDataRelativePath)) { m_dicDefaultFileOwners.Remove(strDataRelativePath); } } if (ProgressWorker.Cancelled()) { return; } ProgressWorker.StepItemProgress(); } }
/// <summary> /// Creates a fomod from a source. /// </summary> /// <remarks> /// The source can be a folder or an archive. /// </remarks> /// <param name="p_strPath">The path to the source from which to create the fomod.</param> /// <param name="p_nxaNexus">An initialized website API from which to retireve mod info.</param> /// <returns>The path to the new fomod if it was successfully built; <lang cref="null"/> otherwise.</returns> public IList<string> BuildFomodFromSource(string p_strPath, NexusAPI p_nxaNexus) { string strSource = p_strPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); List<string> lstPackedFOModPaths = new List<string>(); bool booCreateFromFolder = true; if (File.Exists(strSource)) { booCreateFromFolder = false; if (!Archive.IsArchive(strSource)) throw new ArgumentException("Unrecognized file format.", "p_strPath"); string[] strFOMods = null; using (Archive arcMod = new Archive(strSource)) { strFOMods = arcMod.GetFiles(null, "*.fomod"); if ((strFOMods.Length == 0) && (arcMod.VolumeFileNames.Length > 1)) { if (MessageBox.Show("This mod consists of " + arcMod.VolumeFileNames.Length + " files. It needs to be extracted and repacked.", "Repack Required", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel) return lstPackedFOModPaths; booCreateFromFolder = true; } } if (!booCreateFromFolder) { if (strFOMods.Length > 0) { foreach (string strFOMod in strFOMods) { string strNewPath = Path.Combine(Program.GameMode.ModDirectory, Path.GetFileName(strFOMod)); if (CheckFileName(ref strNewPath)) { using (SevenZipExtractor szeExtractor = Archive.GetExtractor(strSource)) { using (FileStream fsmFOMod = new FileStream(strNewPath, FileMode.Create)) szeExtractor.ExtractFile(strFOMod, fsmFOMod); } lstPackedFOModPaths.Add(strNewPath); } } } else { fomod mof = new fomod(strSource, false); if (!mof.HasInstallScript && mof.RequiresScript) { if (MessageBox.Show("This mod requires a script to install properly, but doesn't have one." + Environment.NewLine + "Would you like to continue?", "Missing Script", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.No) return lstPackedFOModPaths; } //remove the file extension string strPackedFomodPath = Path.GetFileNameWithoutExtension(strSource); //remove the .part1 or what have for multipart files strPackedFomodPath = Path.GetFileNameWithoutExtension(strPackedFomodPath); strPackedFomodPath = Path.Combine(Program.GameMode.ModDirectory, strPackedFomodPath); if (!strPackedFomodPath.EndsWith(".fomod", StringComparison.OrdinalIgnoreCase)) strPackedFomodPath += ".fomod"; string strNewPath = strPackedFomodPath; if (CheckFileName(ref strNewPath)) { FileUtil.ForceDelete(strNewPath); if (MessageBox.Show("Make a copy of the original file?", "", MessageBoxButtons.YesNo) != DialogResult.Yes) File.Move(strSource, strNewPath); else File.Copy(strSource, strNewPath, true); lstPackedFOModPaths.Add(strNewPath); } } } } if (booCreateFromFolder) { string strFomodName = null; if (File.Exists(strSource)) { //remove the file extension strFomodName = Path.GetFileNameWithoutExtension(strSource); //remove the .part1 or what have for multipart files strFomodName = Path.GetFileNameWithoutExtension(strFomodName); } else { Int32 intLastSeparatorPos = strSource.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); strFomodName = strSource.Substring(intLastSeparatorPos + 1); } string strPackedFomodPath = Path.Combine(Program.GameMode.ModDirectory, strFomodName + ".fomod"); strPackedFomodPath = GenerateFomod(new BuildFomodArgs(strFomodName, strSource, null, strPackedFomodPath)); if (!String.IsNullOrEmpty(strPackedFomodPath)) lstPackedFOModPaths.Add(strPackedFomodPath); } ModInfo mifInfo = null; if (Properties.Settings.Default.addMissingInfoToMods) { mifInfo = p_nxaNexus.GetFileInfoGuessVersion(strSource, true); if (mifInfo != null) { foreach (string strFomod in lstPackedFOModPaths) { fomod fomodMod = new fomod(strFomod); fomodMod.SetMissingInfo(mifInfo); } } } return lstPackedFOModPaths; }
/// <summary> /// Creates a mod upgrade script for the given <see cref="fomod" />. /// </summary> /// <param name="p_fomodMod">The mod for which to create an installer script.</param> /// <param name="p_mibInstaller">The installer for which the script is being created.</param> /// <returns>A mod upgrade script for the given <see cref="fomod" />.</returns> public abstract ModInstallScript CreateUpgradeScript(fomod p_fomodMod, ModInstallerBase p_mibInstaller);
/// <summary> /// Updates a mod's information in the install log. /// </summary> /// <remarks> /// This updates the given mod's version and base name in the install log without changing its key. /// </remarks> /// <param name="p_strOldBaseName">The old base name of the mod whose information is to be updated.</param> /// <param name="p_fomodMod">The <see cref="fomod"/> containing the new information.</param> /// <returns><lang cref="true"/> if the given fomod was found and it's information updated; /// <lang cref="false"/> otherwise.</returns> protected bool UpdateMod(string p_strOldBaseName, fomod p_fomodMod) { if (p_fomodMod.BaseName.Equals(p_strOldBaseName)) return UpdateMod(p_fomodMod); if (m_dicModList.ContainsKey(p_strOldBaseName)) { string strKey = GetModKey(p_strOldBaseName); XmlNode xndMod = m_xelModListNode.SelectSingleNode("mod[@key=\"" + strKey + "\"]"); xndMod.Attributes["name"].InnerText = p_fomodMod.BaseName; m_dicModList.Remove(p_strOldBaseName); m_dicModList.Add(p_fomodMod.BaseName, strKey); return UpdateMod(p_fomodMod); } return false; }
/// <summary> /// Upgrades the Install Log to the current version from version 0.0.0.0. /// </summary> /// <remarks> /// This method is called by a background worker to perform the actual upgrade. /// </remarks> protected override void DoUpgrade() { InstallLog.Current.Reset(); var strModInstallFiles = Directory.GetFiles(Program.GameMode.ModDirectory, "*.XMl", SearchOption.TopDirectoryOnly); ProgressWorker.OverallProgressStep = 1; ProgressWorker.OverallProgressMaximum = strModInstallFiles.Length; ProgressWorker.ItemProgressStep = 1; foreach (var strModInstallLog in strModInstallFiles) { if (ProgressWorker.Cancelled()) { return; } var strFomodPath = Path.ChangeExtension(strModInstallLog, ".fomod"); if (File.Exists(strFomodPath)) { var xmlModInstallLog = new XmlDocument(); xmlModInstallLog.Load(strModInstallLog); //figure out how much work we need to do for this mod var xnlFiles = xmlModInstallLog.SelectNodes("descendant::installedFiles/*"); var xnlIniEdits = xmlModInstallLog.SelectNodes("descendant::iniEdits/*"); var xnlSdpEdits = xmlModInstallLog.SelectNodes("descendant::sdpEdits/*"); var intItemCount = xnlFiles.Count + xnlIniEdits.Count + xnlSdpEdits.Count; ProgressWorker.ItemMessage = Path.GetFileNameWithoutExtension(strModInstallLog); ProgressWorker.ItemProgress = 0; ProgressWorker.ItemProgressMaximum = intItemCount; var fomodMod = new fomod(strFomodPath); var strModBaseName = fomodMod.BaseName; InstallLog.Current.AddMod(fomodMod); m_dicDefaultFileOwners = new Dictionary <string, string>(); UpgradeInstalledFiles(xmlModInstallLog, fomodMod, strModBaseName); //we now have to tell all the remaining default owners that are are indeed // the owners foreach (var kvpOwner in m_dicDefaultFileOwners) { MakeOverwrittenModOwner(kvpOwner.Value, kvpOwner.Key); } if (ProgressWorker.Cancelled()) { return; } UpgradeIniEdits(xmlModInstallLog, strModBaseName); if (ProgressWorker.Cancelled()) { return; } UpgradeSdpEdits(xmlModInstallLog, strModBaseName); if (ProgressWorker.Cancelled()) { return; } if (File.Exists(strModInstallLog + ".bak")) { FileManager.Delete(strModInstallLog + ".bak"); } FileManager.Move(strModInstallLog, strModInstallLog + ".bak"); } ProgressWorker.StepOverallProgress(); } InstallLog.Current.SetInstallLogVersion(InstallLog.CURRENT_VERSION); InstallLog.Current.Save(); }
/// <summary> /// Merges the installed and edited components in the given <see cref="InstallLogMergeModule"/> /// into the install log for the specified mod, as an in-place upgrade. /// </summary> /// <remarks> /// When a <see cref="InstallLogMergeModule"/> is merged as an in-place upgrade, any files/changes /// that exist in the install log for the given fomod are replaced where they are in the install /// order, rather than being made the file/change owner (unless they already where the file/change /// owner). Note, however, that if the merge module contains new files/changes that the previous fomod /// version did not contain the fomods will become the owner of the new files/changes. /// /// Also, changes that are logged for the speicifed fomod that are not in the given /// <see cref="InstallLogMergeModule"/> are removed from the install log. /// </remarks> /// <param name="p_fomodMod">The <see cref="fomod"/> for which the /// installs and edits where made.</param> /// <param name="p_strOldBaseName">The old base name of the fomod that is being upgraded. This is the /// base name that will be replaced with the base name of the given fomod.</param> /// <param name="p_ilmMergeModule">The installs and edits that where made as part of the /// <see cref="fomod"/>'s upgrade.</param> public void MergeUpgrade(fomod p_fomodMod, string p_strOldBaseName, InstallLogMergeModule p_ilmMergeModule) { if (!UpdateMod(p_strOldBaseName, p_fomodMod)) AddMod(p_fomodMod); //remove changes that were not made in the upgrade InstallLogMergeModule ilmPreviousChanges = GetMergeModule(p_fomodMod.BaseName); foreach (string strFile in ilmPreviousChanges.DataFiles) if (!p_ilmMergeModule.ContainsFile(strFile)) RemoveDataFile(p_fomodMod.BaseName, strFile); foreach (InstallLogMergeModule.IniEdit iniEdit in ilmPreviousChanges.IniEdits) if (!p_ilmMergeModule.IniEdits.Contains(iniEdit)) RemoveIniEdit(p_fomodMod.BaseName, iniEdit.File, iniEdit.Section, iniEdit.Key); foreach (InstallLogMergeModule.GameSpecificValueEdit gsvEdit in ilmPreviousChanges.GameSpecificValueEdits) if (!p_ilmMergeModule.GameSpecificValueEdits.Contains(gsvEdit)) RemoveGameSpecificValueEdit(p_fomodMod.BaseName, gsvEdit.Key); //add/replace changes foreach (string strFile in p_ilmMergeModule.ReplacedOriginalDataFiles) AddDataFile(ORIGINAL_VALUES, strFile); foreach (string strFile in p_ilmMergeModule.DataFiles) ReplaceDataFile(p_fomodMod.BaseName, strFile); foreach (InstallLogMergeModule.IniEdit iniEdit in p_ilmMergeModule.ReplacedOriginalIniValues) AddIniEdit(iniEdit.File, iniEdit.Section, iniEdit.Key, ORIGINAL_VALUES, iniEdit.Value); foreach (InstallLogMergeModule.IniEdit iniEdit in p_ilmMergeModule.IniEdits) ReplaceIniEdit(iniEdit.File, iniEdit.Section, iniEdit.Key, p_fomodMod.BaseName, iniEdit.Value); foreach (InstallLogMergeModule.GameSpecificValueEdit gsvEdit in p_ilmMergeModule.ReplacedGameSpecificValueData) AddGameSpecificValueEdit(ORIGINAL_VALUES, gsvEdit.Key, gsvEdit.Data); foreach (InstallLogMergeModule.GameSpecificValueEdit gsvEdit in p_ilmMergeModule.GameSpecificValueEdits) ReplaceGameSpecificValueEdit(p_fomodMod.BaseName, gsvEdit.Key, gsvEdit.Data); Save(); }
/// <summary> /// Creates a fomod from a source. /// </summary> /// <remarks> /// The source can be a folder or an archive. /// </remarks> /// <param name="p_strPath">The path to the source from which to create the fomod.</param> /// <returns>The path to the new fomod if it was successfully built; <lang langref="null" /> otherwise.</returns> public IList<string> BuildFomodFromSource(string p_strPath) { var strSource = p_strPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var lstPackedFOModPaths = new List<string>(); var booCreateFromFolder = true; if (File.Exists(strSource)) { booCreateFromFolder = false; if (!Archive.IsArchive(strSource)) { throw new ArgumentException("Unrecognized file format.", "p_strPath"); } string[] strFOMods; using (var arcMod = new Archive(strSource)) { strFOMods = arcMod.GetFiles(null, "*.fomod"); if ((strFOMods.Length == 0) && (arcMod.VolumeFileNames.Length > 1)) { if ( MessageBox.Show( "This mod consists of " + arcMod.VolumeFileNames.Length + " files. It needs to be extracted and repacked.", "Repack Required", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel) { return lstPackedFOModPaths; } booCreateFromFolder = true; } } if (!booCreateFromFolder) { if (strFOMods.Length > 0) { foreach (var strFOMod in strFOMods) { var strNewPath = Path.Combine(Program.GameMode.ModDirectory, Path.GetFileName(strFOMod)); if (CheckFileName(ref strNewPath)) { using (var szeExtractor = Archive.GetExtractor(strSource)) { using (var fsmFOMod = new FileStream(strNewPath, FileMode.Create)) { szeExtractor.ExtractFile(strFOMod, fsmFOMod); } } lstPackedFOModPaths.Add(strNewPath); } } } else { var mof = new fomod(strSource, false); if (!mof.HasInstallScript && mof.RequiresScript) { if ( MessageBox.Show( "This mod requires a script to install properly, but doesn't have one." + Environment.NewLine + "Would you like to continue?", "Missing Script", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.No) { return lstPackedFOModPaths; } } //remove the file extension var strPackedFomodPath = Path.GetFileNameWithoutExtension(strSource); strPackedFomodPath = Path.Combine(Program.GameMode.ModDirectory, strPackedFomodPath); if (!strPackedFomodPath.EndsWith(".fomod", StringComparison.OrdinalIgnoreCase)) { strPackedFomodPath += ".fomod"; } var strNewPath = strPackedFomodPath; if (CheckFileName(ref strNewPath)) { FileUtil.ForceDelete(strNewPath); File.Copy(strSource, strNewPath, true); lstPackedFOModPaths.Add(strNewPath); } } } } if (booCreateFromFolder) { string strFomodName; if (File.Exists(strSource)) { //remove the file extension strFomodName = Path.GetFileNameWithoutExtension(strSource); } else { var intLastSeparatorPos = strSource.LastIndexOfAny(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); strFomodName = strSource.Substring(intLastSeparatorPos + 1); } var strPackedFomodPath = Path.Combine(Program.GameMode.ModDirectory, strFomodName + ".fomod"); strPackedFomodPath = GenerateFomod(new BuildFomodArgs(strFomodName, strSource, null, strPackedFomodPath)); if (!String.IsNullOrEmpty(strPackedFomodPath)) { lstPackedFOModPaths.Add(strPackedFomodPath); } } return lstPackedFOModPaths; }
/// <summary> /// Updates a mod's information in the install log. /// </summary> /// <remarks> /// This updates the given mod's version in the install log without changing its key. /// </remarks> /// <param name="p_fomodMod">The <see cref="fomod"/> being updated.</param> /// <returns><lang cref="true"/> if the given fomod was found and it's information updated; /// <lang cref="false"/> otherwise.</returns> protected internal bool UpdateMod(fomod p_fomodMod) { if (m_dicModList.ContainsKey(p_fomodMod.BaseName)) { XmlNode xndMod = m_xelModListNode.SelectSingleNode("mod[@key=\"" + GetModKey(p_fomodMod.BaseName) + "\"]"); XmlNode xndVersion = xndMod.SelectSingleNode("version"); if (xndVersion == null) { xndVersion = xndMod.AppendChild(xmlDoc.CreateElement("version")); xndVersion.Attributes.Append(xmlDoc.CreateAttribute("machineVersion")); } xndVersion.Attributes["machineVersion"].InnerText = p_fomodMod.MachineVersion.ToString(); xndVersion.InnerText = p_fomodMod.HumanReadableVersion; return true; } return false; }
/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> to be upgraded.</param> internal ModUpgrader(fomod p_fomodMod, string p_strOldBaseName) : base(new UpgradeFomod(p_fomodMod.filepath)) { m_fomodOriginalMod = p_fomodMod; ((UpgradeFomod) Fomod).SetBaseName(p_strOldBaseName); }
/// <summary> /// A simple constructor that initializes teh object with the given values. /// </summary> /// <param name="p_xmlConfig">The modules configuration file.</param> /// <param name="p_fomodMod">The mod whose configuration file we are parsing.</param> /// <param name="p_dsmSate">The state of the install.</param> /// <param name="p_pexParserExtension">The parser extension that provides game-specific config file parsing.</param> public Parser50(XmlDocument p_xmlConfig, fomod p_fomodMod, DependencyStateManager p_dsmSate, ParserExtension p_pexParserExtension) : base(p_xmlConfig, p_fomodMod, p_dsmSate, p_pexParserExtension) {}
/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> against which to run the script.</param> public FalloutNewVegasModInstallScript(fomod p_fomodMod, ModInstallerBase p_mibInstaller) : base(p_fomodMod, p_mibInstaller) { }
/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> to be upgraded.</param> internal ModUpgrader(fomod p_fomodMod) : this(p_fomodMod, p_fomodMod.BaseName) { }
/// <summary> /// Creates a mod upgrade script for the given <see cref="fomod" />. /// </summary> /// <param name="p_fomodMod">The mod for which to create an installer script.</param> /// <param name="p_mibInstaller">The installer for which the script is being created.</param> /// <returns>A mod upgrade script for the given <see cref="fomod" />.</returns> public override ModInstallScript CreateUpgradeScript(fomod p_fomodMod, ModInstallerBase p_mibInstaller) { return(new FalloutNewVegasModUpgradeScript(p_fomodMod, p_mibInstaller)); }
/// <summary> /// A simple constructor that initializes teh object with the given values. /// </summary> /// <param name="p_xmlConfig">The modules configuration file.</param> /// <param name="p_fomodMod">The mod whose configuration file we are parsing.</param> /// <param name="p_dsmSate">The state of the install.</param> /// <param name="p_pexParserExtension">The parser extension that provides game-specific config file parsing.</param> public Parser10(XmlDocument p_xmlConfig, fomod p_fomodMod, DependencyStateManager p_dsmSate, ParserExtension p_pexParserExtension) : base(p_xmlConfig, p_fomodMod, p_dsmSate, p_pexParserExtension) { }
/// <summary> /// A simple constructor that initializes the object. /// </summary> /// <param name="p_fomodMod">The <see cref="fomod" /> against which to run the script.</param> public Fallout3ModUpgradeScript(fomod p_fomodMod, ModInstallerBase p_mibInstaller) : base(p_fomodMod, p_mibInstaller) { }